Zadanie:
Masz listę peopleobiektów klasy, Personktóra ma pola namei age. Twoim zadaniem jest posortowanie tej listy najpierw według name, a następnie według age.
Java 7:
Collections.sort(people, new Comparator<Person>() {
public int compare(Person a, Person b) {
return a.getName().compare(b.getName());
}
});
Collections.sort(people, new Comparator<Person>() {
public int compare(Person a, Person b) {
return Integer.valueOf(a.getAge()).compare(b.getAge());
}
});
Scala:
val sortedPeople = people.sortBy(p => (p.name, p.age))
Aktualizacja
Odkąd napisałem tę odpowiedź, nastąpił spory postęp. Lambdy (i odwołania do metod) w końcu wylądowały w Javie i szturmem podbijają świat Javy.
Tak będzie wyglądał powyższy kod z Javą 8 (nadesłana przez @fredoverflow):
people.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));
Chociaż ten kod jest prawie tak krótki, nie działa tak elegancko jak kod Scala.
W roztworze Scala The Seq[A]#sortBysposób przyjmuje funkcję A => B, gdzie Bjest wymagane, aby miećOrdering . Orderingjest klasą typu. Pomyśl najlepiej o obu światach: tak jak Comparable, jest to niejawne dla danego typu, ale podobnie Comparator, jest rozszerzalne i może być dodane retrospektywnie do typów, które go nie miały. Ponieważ w Javie brakuje klas typów, musi ona powielać każdą taką metodę, raz na Comparable, potem na Comparator. Na przykład zobacz comparingi thenComparing tutaj .
Klasy typów pozwalają na pisanie reguł, takich jak „Jeśli A ma porządek, a B ma porządek, to ich krotka (A, B) również ma uporządkowanie”. W kodzie to znaczy:
implicit def pairOrdering[A : Ordering, B : Ordering]: Ordering[(A, B)] = // impl
W ten sposób sortByw naszym kodzie można porównać nazwę, a następnie wiek. Ta semantyka zostanie zakodowana powyższą „regułą”. Programista Scala intuicyjnie spodziewałby się, że to zadziała w ten sposób. Żadnych specjalnych metod, takich jak comparingnie trzeba było dodawaćOrdering .
Lambdy i odwołania do metod to tylko wierzchołek góry lodowej, jaką jest programowanie funkcjonalne. :)