2015-08-03 20 views
18

Così ho una collezione di oggetti che hanno una variabile passo che può essere 1 - 4.Java 8 Stream - .max() con i duplicati

public class MyClass { 
    private Long step; 

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

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

Poi vorrei ottenere un'istanza MyClass dalla collezione che ha il valore massimo passaggio, quindi fare:

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

Tuttavia, vi sono situazioni in cui ci saranno più MyClass ins tance nella raccolta che hanno un passo uguale a 4.

Quindi, la mia domanda è, come viene determinata quale istanza viene restituita nello Optional o genera un'eccezione quando più oggetti nel flusso hanno il valore massimo che viene confrontato?

La documentazione Java 8 per la funzione max() non specifica cosa si verificherà in questa situazione.

+1

Perché l'ordine è importante se sono uguali? – the8472

+2

Per l'esempio particolare in cui lo sto usando, non ha molta importanza, dal momento che sto solo tirando il passo dall'oggetto restituito. Tuttavia, ci sono altre variabili nella classe, quindi essere sullo stesso passo non significa che gli oggetti siano uguali. Quindi in altre situazioni, potrebbe importare quale oggetto viene restituito. Il motivo della mia domanda era principalmente capire come funziona la funzione 'max()' quando più oggetti hanno lo stesso valore nel campo che viene confrontato. –

+2

E perché non usare un comparatore concatenato che includa quelle altre variabili se contano? – the8472

risposta

15

max è implementato riducendo la collezione con maxBy:

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

Qui comparator.compare(a, b) >= 0 ? a : b si può vedere che quando 2 elementi sono uguali, vale a dire compare restituisce 0, quindi il primo elemento viene restituito. Pertanto nel tuo caso verrà restituito prima in una collezione MyClass oggetto con il massimo step.

UPDATE: Come utente the8472 menzionato correttamente nei commenti, non si dovrebbe fare affidamento su di attuazione che non è esplicitamente specificato da javadocs. Ma puoi scrivere un test unitario sul metodo max per sapere se la logica è cambiata nella libreria java standard.

+12

finché i javadocs non specificano il comportamento, non si dovrebbe fare affidamento sull'implementazione. – the8472

10

Poiché l'ordine non è specificato dalla documentazione, l'ordine può essere diverso nelle versioni future della JVM o in diverse implementazioni della JVM.

Se si cura quale viene restituito, il mio consiglio è di scrivere la propria operazione di riduzione o il Collezionista di comportarsi come si desidera. In questo modo le future implementazioni non possono cambiarlo e puoi dire esplicitamente cosa accadrà.

+6

C'è una connessione qui al comportamento di 'sorted()' e 'distinct()'. Le operazioni di ordinamento sono stabili se il flusso è ordinato e non sono altrimenti stabili.Analogamente, l'operazione 'distinct' restituisce l'istanza _prima_ di ogni classe di equivalenza se il flusso è ordinato. E la riduzione rispetta anche l'ordine dell'incontro se il flusso è ordinato. Quello che manca è che min/max non si impegnano a questo - ma probabilmente dovrebbero. –

+0

@BrianGoetz Pensi che sia probabile che le versioni future si impegnino in cose come questa? Un problema simile che ho è con 'Collectors.toList()' che non si impegna sul tipo o sulla mutabilità del 'List' restituito. Sarebbe davvero bello avere garanzie per questo genere di cose. –

+9

I due esempi non potrebbero essere più diversi. C'è una ragionevole argomentazione che la cosa minima/massima è solo una svista, e quindi c'è una possibilità che potremmo correggerla. La cosa 'toList()' non era una svista: era il punto! Quindi non c'è possibilità che cambieremmo. La totale mancanza di impegno è dovuta alla progettazione - per massimizzare la flessibilità di implementazione. (E abbiamo incluso semplici alternative: se vuoi un 'ArrayList', puoi usare' toCollection (ArrayList :: new) '.) –

Problemi correlati