2015-10-01 12 views
59

Ho un elenco di oggetti che dice car. Voglio filtrare questo elenco in base ad alcuni parametri utilizzando Java 8. Ma se il parametro è null, genera NullPointerException. Come filtrare i valori nulli?Valori del filtro solo se non null utilizzando lambda in Java8

codice attuale è la seguente

requiredCars = cars.stream().filter(c -> c.getName().startsWith("M")); 

Questo getta NullPointerException se getName() rendimenti null.

+0

ti voglio “valori di filtro solo se non nullo "O" filtra i valori nulli "? Mi sembra contraddittorio. – Holger

+1

Potrei suggerire di accettare [la risposta di Tunaki] (http://stackoverflow.com/a/32884225/42473) in quanto sembra essere l'unica che risponde effettivamente alla tua domanda. –

risposta

22

Hai solo bisogno di filtrare le auto che hanno un nome null:

requiredCars = cars.stream() 
        .filter(c -> c.getName() != null) 
        .filter(c -> c.getName().startsWith("M")); 
+0

È un vero peccato che questa risposta non sia più votata in quanto sembra essere l'unica risposta che risponde effettivamente alla domanda. –

+0

@MarkBooth La domanda "Come filtrare valori nulli?" sembra essere ben risposto da xbakesx. – vegemite4me

+0

@MarkBooth Guardando le date siete corretti. Errore mio. – vegemite4me

17

È possibile eseguire questa operazione in fase filtro singolo:

requiredCars = cars.stream().filter(c -> c.getName() != null && c.getName().startsWith("M")); 

Se non si desidera chiamare getName() diversi volte (ad esempio, è costosa chiamata), è possibile effettuare questa operazione:

requiredCars = cars.stream().filter(c -> { 
    String name = c.getName(); 
    return name != null && name.startsWith("M"); 
}); 

O in modo più sofisticato:

requiredCars = cars.stream().filter(c -> 
    Optional.ofNullable(c.getName()).filter(name -> name.startsWith("M")).isPresent()); 
151

In questo particolare esempio penso @Tagir è corretta al 100% lo fanno in un filtro e fare le due assegni. Non userei lo Optional.ofNullable il materiale opzionale è davvero per i tipi di ritorno che non devono fare la logica ... ma in realtà né qui né lì.

ho voluto sottolineare che java.util.Objects ha un bel metodo per questo in un caso ampio, in modo da poter fare questo:

cars.stream() 
    .filter(Objects::nonNull) 

che annullerà i vostri oggetti nulli. Per chi non lo conoscesse, questo è il breve mano per i seguenti:

cars.stream() 
    .filter(car -> Objects.nonNull(car)) 

Per rispondere pienamente alla domanda a portata di mano per restituire l'elenco delle vetture che hanno un nome e comincia con "M":

cars.stream() 
    .filter(car -> Objects.nonNull(car)) 
    .map(car -> car.getName()) 
    .filter(carName -> Objects.nonNull(carName)) 
    .filter(carName -> carName.startsWith("M")) 
    .collect(Collectors.toList()); 

volta ci si abitua alle lambda stenografia si potrebbe anche fare questo:

cars.stream() 
    .filter(Objects::nonNull) 
    .map(Car::getName)  // Assume the class name for car is Car 
    .filter(Objects::nonNull) 
    .filter(carName -> carName.startsWith("M")) 
    .collect(Collectors.toList()); 
+0

nota che l'auto nullo non è il problema. In questo caso, è la proprietà name a causare problemi. Quindi 'Objects :: nonNull' non può essere usato qui, e nell'ultimo consiglio dovrebbe essere' cars.stream() .filter (car -> Objects.nonNull (car.getName())) 'Credo che – kiedysktos

+1

BTW , Penso 'cars.stream() . Filtro (auto -> Objects.nonNull (car.getName()) && car.getName(). StartsWith (" M "))' sarebbe il riepilogo del tuo consiglio in questo contesto domanda – kiedysktos

+3

@kiedysktos Questo è un buon punto che chiamare ".startWith' potrebbe anche causare un puntatore nullo. Il punto che stavo cercando di fare è che Java fornisce un metodo specifico per filtrare oggetti nulli dai tuoi stream. – xbakesx

18

le risposte proposte sono grandi. Proprio vorrebbe suggerire un miglioramento per gestire il caso di lista nulla usando Optional.ofNullable, new feature in Java 8:

List<String> carsFiltered = Optional.ofNullable(cars) 
       .orElseGet(Collections::emptyList) 
       .stream() 
       .filter(Objects::nonNull) 
       .collect(Collectors.toList()); 

Quindi, la risposta completa sarà:

List<String> carsFiltered = Optional.ofNullable(cars) 
       .orElseGet(Collections::emptyList) 
       .stream() 
       .filter(Objects::nonNull) //filtering car object that are null 
       .map(Car::getName) //now it's a stream of Strings 
       .filter(Objects::nonNull) //filtering null in Strings 
       .filter(name -> name.startsWith("M")) 
       .collect(Collectors.toList()); //back to List of Strings 
+3

Uso errato di Opzionale. null non dovrebbe mai essere utilizzato come sinonimo di una raccolta vuota in primo luogo. – VGR

+3

@ VGR Certo, ma non è quello che succede nella pratica. A volte (la maggior parte delle volte) è necessario lavorare con il codice su cui molte persone hanno lavorato. A volte ricevi i tuoi dati da interfacce esterne. Per tutti questi casi, Opzionale è un grande uso. – Stas

+1

nota che l'auto nulla non è il problema. In questo caso, è la proprietà name a causare problemi. Quindi 'Objects :: nonNull' non risolve il problema poiché l'auto non nulla può avere nome == null – kiedysktos

Problemi correlati