Sortowanie obiektów w Javie

Temat stary jak świat, jednak często powraca, gdyż nie każdy wie lub pamięta, w jaki sposób skutecznie posortować obiekty w Javie.

W tym krótkim wpisie przypomnę i pokażę jak to zrobić, zwłaszcza w przypadku streamów, które czasem mogą lekko zaskoczyć.

Wymagania

  • Java 8
  • 15 minut wolnego czasu

Interfejs Comparable

Aby prawidłowo posortować dowolny obiekt musimy zaimplementować na nim interfejs Comparable.

Interfejs ten ma jedną metodę: compareTo(..), która zwraca int

  • ujemnego jeżeli obiekt porównywany jest mniejszy
  • 0 – jeżeli oba obiekty są takie same
  • dodatniego jeżeli obiekt porównywany jest większy

Napiszmy więc prostą klasę i zaimplementujmy w niej interfejs Comparable

Chcemy, aby obiekt typu Person był sortowany według imienia, a więc napisaliśmy metodę compareTo, która porówna same imiona. String ma swoją wbudowaną metodę compareTo, przez co nie musimy się już martwić jej implementacją.

Sortowanie

Napiszmy prostą listę z kilkoma obiektami typu Person:

Teraz ją posortujmy:

Wynik -> posortowana lista osób:

[Person{name=’Anna’, lastName=’Piotrowska’}, Person{name=’Janek’, lastName=’Kowalski’}, Person{name=’Piotr’, lastName=’Nowak’}]

Jednak ważną uwagą jest to, że zmodyfikowaliśmy kolejność inicjalnej listy, co w dobie programowania funkcyjnego, niemutowalności, nie zawsze jest dobrą lub polecaną praktyką.

Możemy więc użyć streamów:

Czego się spodziewamy? Zapewne wyświetlenia posortowanych imion. Niestety… tak się nie musi stać. Jeśli popatrzymy na dokumentację metody forEach, znajdziemy w niej zapis:

For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism.

Czyli, jeżeli użyjemy wielowątkowości, to sort order nie musi być zachowany.

Na szczęście mamy metodę forEachOrdered 🙂

Tutaj już mamy posortowane imiona.

Natomiast, jeżeli chcemy zwrócić listę posortowaną, to już nie mamy z tym problemu:

Tym samym stworzyliśmy nową, posortowaną listę nie modyfikując poprzedniej. Jest to rozwiązanie funkcyjne.

Własny Comparator

Czasami pomimo posiadania interfejsu Comparable, dla jakiejś funkcjonalności potrzebujemy go zmienić. To wcale nie oznacza koszmarnego kodu i siwiejącego programisty złorzeczącego na dostawcę tak porąbanego wymagania 🙂

Przydaje się to też w momencie, kiedy nie mamy dostępu do klasy i nie mamy jak w niej zaimplementować interfejsu Comparable.

Zrobiliśmy własny Comparator, za pomocą którego posortowaliśmy listę, tym razem według nazwisk. Możemy ją też odwrócić jeśli trzeba:

Za pomocą streamów jest podobnie:

 

Sortowanie jest dość proste, o ile wiemy po czym mamy sortować. Reszta jest tylko odpowiednim użyciem kilku nieskomplikowanych metod 🙂

 

Złota myśl mojej Żony: Jak pada deszcz to internet wolniej chodzi, bo musi omijać kropelki.