Подтвердить что ты не робот

Фильтровать значения, если не null, используя lambda в Java8

У меня есть список объектов: car. Я хочу отфильтровать этот список на основе некоторого параметра, используя Java 8. Но если параметр null, он выдает NullPointerException. Как отфильтровать нулевые значения?

Текущий код выглядит следующим образом

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

Это бросает NullPointerException, если getName() возвращает null.

4b9b3361

Ответ 1

В этом конкретном примере я думаю, что @Tagir на 100% корректен, поместите его в один фильтр и выполните две проверки. Я бы не использовал Optional.ofNullable Optional - это действительно то, что типы возвращаемых данных не должны выполнять логику... но на самом деле ни здесь, ни там.

Я хотел бы отметить, что java.util.Objects имеет хороший метод для этого в широком случае, так что вы можете сделать это:

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

Который очистит ваши нулевые объекты. Для тех, кто не знаком, это сокращение для следующего:

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

Чтобы частично ответить на поставленный вопрос, вернем список имен автомобилей, который начинается с буквы "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());

Как только вы привыкнете к сокращенной лямбде, вы также можете сделать это:

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

К сожалению, как только вы .map(Car::getName) вы будете возвращать только список имен, а не автомобили. Так менее красиво, но полностью отвечает на вопрос:

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

Ответ 2

Вам просто нужно отфильтровать автомобили с именем null:

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

Ответ 3

Предлагаемые ответы великолепны. Просто хотел бы предложить улучшение для обработки случая нулевого списка, используя Optional.ofNullable, новую функцию в Java 8:

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

Итак, полный ответ будет:

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

Ответ 4

Вы можете сделать это одним шагом фильтра:

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

Если вы не хотите вызывать getName() несколько раз (например, это дорогостоящий вызов), вы можете сделать это:

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

Или более сложным способом:

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

Ответ 5

Вы можете использовать это

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