2015-08-03 19 views
18

Więc mam kolekcji obiektów, które mają zmienną krok, który może być 1 - 4.Java 8 Stream - .max() z duplikatów

public class MyClass { 
    private Long step; 

    //other variables, getters, setters, etc. 
} 

Collection<MyClass> myOjbects = /*get collection*/;

Następnie chciałbym dostać jedna instancja MyClass z kolekcji, która ma maksymalną wartość kroku, tak robię:

final Optional<MyClass> objectWithMaxStep = 
    myObjects.stream().max(Comparator.comparing(MyClass::getStep)); 

Jednakże istnieją sytuacje, gdzie nie będzie wielokrotnością MyClass ins tances w kolekcji, które mają krok równy 4.

Moje pytanie brzmi: w jaki sposób określa się, która instancja jest zwracana w Optional, czy też generuje wyjątek, gdy wiele obiektów w strumieniu ma wartość maksymalną to jest porównywane?

Dokumentacja Java 8 dla funkcji max() nie określa, co będzie miało miejsce w tej sytuacji.

+1

Dlaczego zamówienie ma znaczenie, jeśli jest równe? – the8472

+2

Dla konkretnego przykładu, dla którego go używam, nie ma to znaczenia, ponieważ tylko wyciągam krok ze zwróconego obiektu. Istnieją jednak inne zmienne w klasie, więc bycie na tym samym etapie nie oznacza, że ​​obiekty są równe. W innych sytuacjach może to mieć znaczenie, który obiekt zostanie zwrócony. Powodem mojego pytania było przede wszystkim zrozumienie, jak działa funkcja 'max()', gdy wiele obiektów ma taką samą wartość w porównywanym polu. –

+2

A dlaczego po prostu nie używać połączonego komparatora, w tym innych zmiennych, jeśli są one ważne? – the8472

Odpowiedz

15

max realizowany jest zmniejszenie poboru z maxBy:

public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) { 
     Objects.requireNonNull(comparator); 
     return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; 
    } 

Tutaj comparator.compare(a, b) >= 0 ? a : b widać, że gdy 2 elementy są równe, tj compare zwraca 0, a następnie pierwszy element jest zwracany. Dlatego w twoim przypadku zostanie zwrócony pierwszy w kolekcji MyClass obiekt o najwyższym step.

UPDATE: Jako użytkownik the8472 poprawnie wspomniano w komentarzach, nie należy polegać na realizacji, który nie jest wyraźnie określony przez Javadocs. Ale możesz napisać test jednostkowy na metodzie max, aby wiedzieć, czy zmieniła się logika w standardowej bibliotece Javy.

+12

tak długo jak javadocs nie określają zachowania, nie powinieneś polegać na implementacji. – the8472

10

Ponieważ zamówienie nie jest określone w dokumentacji, zamówienie może być inne w przyszłych wersjach JVM lub w różnych implementacjach JVM.

Jeśli zależy Ci na tym, który z nich jest zwrócony, moja rada to napisać własną operację redukcji lub Collector, aby zachowywać się jak chcesz. W ten sposób przyszłe wdrożenia nie mogą tego zmienić i możesz wyraźnie powiedzieć, co się stanie.

+6

Istnieje tu połączenie z zachowaniem 'sorted()' i 'distinct()'. Operacje sortowania są stabilne, jeśli strumień jest uporządkowany, a nie stabilny w przeciwnym razie.Analogicznie operacja 'distinct' zwraca pierwszą instancję każdej klasy równoważności, jeśli strumień jest uporządkowany. A redukcja uwzględnia także kolejność spotkań, jeśli strumień jest uporządkowany. Brakuje tego, że min/max nie angażują się w to - ale prawdopodobnie powinni. –

+0

@ BrianGoetz Czy sądzisz, że prawdopodobne jest, że przyszłe wersje zaakceptują takie rzeczy? Podobny problem mam z 'Collectors.toList()', który nie zatwierdza typu, a nawet zmienności zwracanej 'List'. Byłoby naprawdę miło mieć gwarancje na tego typu rzeczy. –

+9

Dwa przykłady nie mogą być bardziej różne. Istnieje uzasadniony argument, że min/max to tylko niedopatrzenie, a zatem istnieje szansa, że ​​możemy to poprawić. Rzecz 'toList()' nie była przeoczeniem - to była cała uwaga! Więc nie ma szans, żebyśmy to zmienili. Całkowity brak zaangażowania wynika z projektu - w celu maksymalizacji elastyczności wdrożenia. (I dodaliśmy proste alternatywy, jeśli chcesz 'ArrayList', możesz użyć' toCollection (ArrayList :: new) '.) –