仅在 Java8 中使用 lambda 不为 null 时才过滤值

Filter values only if not null using lambda in Java8

提问人:vaibhavvc1092 提问时间:10/1/2015 最后编辑:Tagir Valeevvaibhavvc1092 更新时间:9/21/2022 访问量:428806

问:

我有一个对象列表说.我想使用 Java 8 根据某些参数过滤此列表。但是如果参数是 ,则抛出 .如何过滤掉空值?carnullNullPointerException

当前代码如下

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

这将抛出 if 返回 .NullPointerExceptiongetName()null

java lambda nullpointerexception null java-8

评论

0赞 Holger 10/1/2015
是否要“仅筛选值,而不是 null”或“筛选出 null 值”?这听起来与我相矛盾。
3赞 Mark Booth 5/4/2017
我能否建议您接受 Tunaki 的回答,因为它似乎是唯一真正回答您问题的答案。
0赞 JustAnotherCoder 12/18/2021
kotlin 呢?)) requiredCars = cars.filter {c -> c?.名字?。startsWith(“M”))};

答:

89赞 Tunaki 10/1/2015 #1

您只需要过滤有名称的汽车:null

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

评论

5赞 Mark Booth 5/4/2017
很遗憾,这个答案没有得到更多的投票,因为它似乎是唯一真正回答这个问题的答案。
2赞 vegemite4me 6/1/2017
@MarkBooth xbakesx 似乎很好地回答了“如何过滤掉空值”这个问题。
0赞 vegemite4me 6/2/2017
@MarkBooth 看日期你是对的。我的错误。
0赞 Vaibhav_Sharma 3/27/2019
性能方面,过滤流两次好还是更好地使用谓词进行过滤?只是想知道。
32赞 Tagir Valeev 10/1/2015 #2

您可以在单个筛选器步骤中执行此操作:

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

评论

0赞 Paul 3/6/2020
第二个示例中的内联扩展对我的用例很有价值
513赞 xbakesx 5/24/2016 #3

在这个特定示例中,我认为@Tagir 100% 正确,将其放入一个过滤器并进行两次检查。我不会使用可选的东西真的是为了返回类型而不是做逻辑......但实际上既不在这里也不在那里。Optional.ofNullable

我想指出,在广泛的情况下,这有一个很好的方法,所以你可以这样做:java.util.Objects

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

这将清除 null 对象。对于不熟悉的人来说,这是以下内容的简写:

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

一旦你习惯了速记lambda,你也可以这样做:

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

评论

1赞 kiedysktos 1/9/2017
请注意,空车不是问题所在。在这种情况下,是 name 属性导致了问题。所以不能在这里使用,在最后的建议中,我相信它应该是Objects::nonNullcars.stream() .filter(car -> Objects.nonNull(car.getName()))
1赞 kiedysktos 1/9/2017
顺便说一句,我认为这将是您在这个问题背景下的建议的总结cars.stream() .filter(car -> Objects.nonNull(car.getName()) && car.getName().startsWith("M"))
4赞 xbakesx 1/10/2017
@kiedysktos 这是一个很好的观点,调用也可能导致空指针。我想说的是,Java 提供了一种专门用于从流中过滤掉空对象的方法。.startWith
0赞 kiedysktos 5/4/2017
@Mark Booth 是的,显然等同于 ,你的选择更短Objects.nonNull!= null
1赞 user1803551 10/4/2018
您不是创建汽车名称 () 而不是汽车 () 列表吗?StringCar
67赞 Johnny 8/29/2016 #4

建议的答案很棒。只是想提出一个改进建议,以处理使用 Java 8 中的新功能处理列表的情况:nullOptional.ofNullable

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'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

评论

7赞 VGR 12/13/2016
Optional 使用不当。首先,null 不应用作空 Collection 的同义词。
7赞 Johnny 12/13/2016
@VGR 当然,但这不是实践中发生的事情。有时(大多数时候)你需要使用很多人都在处理的代码。有时您会从外部接口接收数据。对于所有这些情况,“可选”都是一个很好的用途。
3赞 kiedysktos 1/9/2017
请注意,空车不是问题所在。在这种情况下,是 name 属性导致了问题。所以不能解决问题,因为非空车可以有 name==nullObjects::nonNull
1赞 Johnny 9/7/2017
当然@kiedysktos,但这不是我想在答案中展示的。但是,我接受你说的话并编辑答案:)
4赞 riverfan 7/19/2019 #5

你可以用这个

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

4赞 rslemos 2/1/2020 #6

利用以下力量:java.util.Optional#map()

List<Car> requiredCars = cars.stream()
  .filter (car -> 
    Optional.ofNullable(car)
      .map(Car::getName)
      .map(name -> name.startsWith("M"))
      .orElse(false) // what to do if either car or getName() yields null? false will filter out the element
    )
  .collect(Collectors.toList())
;

评论

0赞 Florian F 8/22/2023
恕我直言,使用 Optional 的复杂性来替换简单的布尔表达式是不好的做法。