web-dev-qa-db-fra.com

Filtrer les valeurs uniquement si non nul à l'aide de lambda en Java8

J'ai une liste d'objets disons car. Je veux filtrer cette liste en fonction de certains paramètres à l'aide de Java 8. Mais si le paramètre est null, il renvoie NullPointerException. Comment filtrer les valeurs NULL?

Le code actuel est le suivant

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

Ceci jette NullPointerException si getName() renvoie null.

140
vaibhavvc1092

Dans cet exemple particulier, je pense que @Tagir est correct à 100%, insérez-le dans un filtre et effectuez les deux vérifications. Je n'utiliserais pas Optional.ofNullable les options sont en réalité destinées aux types de retour qui ne font pas de logique ... mais vraiment, ni ici ni là-bas.

Je voulais souligner que Java.util.Objects a une méthode de Nice pour cela dans un cas large, vous pouvez donc faire ceci:

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

Ce qui effacera vos objets nuls. Pour ceux qui ne sont pas familiers, c'est le raccourci pour ce qui suit:

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

Pour répondre partiellement à la question en question, renvoyez la liste des noms de voiture commençant par "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());

Une fois que vous vous êtes habitué aux lambdas de sténographie, vous pouvez également le faire:

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());

Malheureusement, une fois que vous .map(Car::getName) vous retournerez uniquement la liste des noms, pas les voitures. Donc, moins belle mais répond pleinement à la question:

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

Vous avez juste besoin de filtrer les voitures qui ont un nom null:

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

Les réponses proposées sont excellentes. Je voudrais juste suggérer une amélioration pour traiter le cas de liste nulle en utilisant Optional.ofNullable, nouvelle fonctionnalité dans Java 8 :

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

Donc, la réponse complète sera:

 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
38
Johnny

Vous pouvez le faire en une seule étape de filtrage:

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

Si vous ne souhaitez pas appeler plusieurs fois getName() (par exemple, c'est un appel coûteux), vous pouvez procéder comme suit:

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

Ou de manière plus sophistiquée:

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

tu peux utiliser ça

List<Car> requiredCars = cars.stream()
    .filter (t->  t!= null && StringUtils.startsWith(t.getName(),"M"))
    .collect(Collectors.toList());

1
riverfan