2015-09-18 3 views
7

In Java 7, se voglio ottenere l'ultimo elemento non nullo di una lista, scrivo qualcosa di simile:Ricevi un ultimo elemento non nullo di elenco utilizzando Java 8

public CustomObject getLastObject(List<CustomObject> list) { 
    for (int index = list.size() - 1; index > 0; index--) { 
     if (list.get(index) != null) { 
      return list.get(index); 
     } 
    } 
    // handling of case when all elements are null 
    // or list is empty 
    ... 
} 

Voglio scrivere un breve codice utilizzando lambda o un'altra caratteristica di Java 8. per esempio, se voglio ottenere il primo elemento non nullo posso scrivere questo:

public void someMethod(List<CustomObject> list) { 
    ..... 
    CustomObject object = getFirstObject(list).orElseGet(/*handle this case*/); 
    ..... 
} 

public Optional<CustomObject> getFirstObject(List<CustomObject> list) { 
    return list.stream().filter(object -> object != null).findFirst(); 
} 

Forse qualcuno sa come risolvere questo problema?

+0

Non è sempre ** sempre una buona idea usare lambda. Data la risposta di @Tunaki è più chiaro al lettore che usa il modo non-lambda. – lschuetze

+1

Correlati: ["Come ottenere lo streaming ordinato da un elenco in ordine inverso in Java 8"] (http://stackoverflow.com/q/29403614/2711488) e ["Il modo più efficace per ottenere l'ultimo elemento di un flusso "] (Http://stackoverflow.com/q/27547519/2711488) – Holger

+0

@lschuetze, imparo solo le possibilità di lambda e voglio sapere come posso decidere problemi semplici usando le nuove funzionalità – ZhenyaM

risposta

10

Una possibile soluzione potrebbe essere per scorrere l'elenco in ordine inverso e mantenere il primo elemento non nullo:

public Optional<CustomObject> getLastObject(List<CustomObject> list) { 
    return IntStream.range(0, list.size()).mapToObj(i -> list.get(list.size() - i - 1)) 
              .filter(Objects::nonNull) 
              .findFirst(); 
} 

noti che non esiste un metodo findLast nella API Flusso perché uno Stream non è necessariamente ordinata o finito.

Un'altra soluzione è quella di scorrere l'elenco e ridurlo mantenendo solo l'elemento corrente. Ciò riduce efficacemente il flusso all'ultimo elemento.

public Optional<CustomObject> getLastObject(List<CustomObject> list) { 
    return list.stream().filter(Objects::nonNull).reduce((a, b) -> b); 
} 
+0

Grazie mille, questo è corretto. – ZhenyaM

+2

@assylias Lo stream restituito da ['Collection.stream()'] (https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#stream--) è sequenziale (per Javadoc) – Tunaki

+1

Ecco perché mi sono collegato alle altre domande, per mostrare che, ad es. usando 'reduce' per ottenere l'ultimo elemento [è una soluzione consolidata] (http://stackoverflow.com/a/27547525/2711488). Funziona anche in esecuzione parallela. La funzione di riduzione deve essere associativa ma non deve essere commutativa. – Holger