Фильтровать значения, если не null, используя lambda в Java8
У меня есть список объектов: car
. Я хочу отфильтровать этот список на основе некоторого параметра, используя Java 8. Но если параметр null
, он выдает NullPointerException
. Как отфильтровать нулевые значения?
Текущий код выглядит следующим образом
requiredCars = cars.stream().filter(c -> c.getName().startsWith("M"));
Это бросает NullPointerException
, если getName()
возвращает null
.
Ответы
Ответ 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());