4 题: 仅当在Java8中使用lambda时不为null时才过滤值

在...创建的问题 Thu, Oct 1, 2015 12:00 AM

我有一个对象列表说car。我想基于使用Java 8的一些参数来过滤此列表。但是如果参数是null,则抛出NullPointerException。如何过滤掉空值?

目前的代码如下

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

如果NullPointerException返回getName(),则抛出null

    
134
  1. 你想“仅在不为空时过滤值”或“过滤掉空值”吗?这听起来与我相矛盾。
    2015-10-01 10:18:46Z
  2. 我能否建议您接受 Tunaki的回答是唯一一个真正回答你问题的人。
    2017-05-04 10:14:17Z
  3. 醇>
    4个答案                              4 跨度>                         

    在这个特定的例子中,我认为@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());
    
        
    278
    2018-10-04 14:21:15Z
    1. 请注意,空车不是问题。在这种情况下,它的名称属性导致问题。所以Objects::nonNull不能在这里使用,在最后的建议中它应该是cars.stream() .filter(car -> Objects.nonNull(car.getName()))我相信
      2017-01-09 11:38:13Z
    2. BTW,我认为cars.stream() .filter(car -> Objects.nonNull(car.getName()) && car.getName().startsWith("M"))将是你在这个问题上下文中的建议摘要
      2017-01-09 11:39:42Z
    3. @ kiedysktos这是一个好点,调用.startWith也可能导致空指针。我试图提出的一点是,Java提供了一种专门用于从流中过滤掉空对象的方法。
      2017-01-10 03:43:09Z
    4. @ Mark Booth是的,显然Objects.nonNull相当于!= null,你的选项更短
      2017-05-04 10:30:53Z
    5. 你不是在创建汽车名称列表(String)而不是汽车(Car)吗?
      2018-10-04 10:12:05Z
    6. 醇>

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

     
    requiredCars = cars.stream()
                       .filter(c -> c.getName() != null)
                       .filter(c -> c.getName().startsWith("M"));
    
        
    46
    2015-10-01 09:43:34Z
    1. 真的很遗憾,这个答案并没有被高度评价,因为它似乎是实际回答这个问题的唯一答案。
      2017-05-04 10:13:06Z
    2. @ MarkBooth问题“如何过滤掉空值?” xbakesx好像回答得很好。
      2017-06-01 15:42:24Z
    3. @ MarkBooth查看您的日期是否正确。我的错误。
      2017-06-01 16:28:26Z
    4. 性能明智是两次过滤流还是最好使用谓词进行过滤?只是想知道。
      2019-03-27 05:43:54Z
    5. 醇>

    建议的答案很棒。只是想建议使用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'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
    2018-10-19 01:15:40Z
    1. 糟糕的使用Optional。 null绝不应该首先用作空集合的同义词。
      2016-12-12 22:20:44Z
    2. @ VGR当然,但这不是实践中发生的事情。有时(大多数情况下)您需要使用许多人工作的代码。有时您从外部接口接收数据。对于所有这些情况,Optional是一个很好的用途。
      2016-12-13 08:44:31Z
    3. 请注意,空车不是问题。在这种情况下,它的名称属性导致问题。所以Objects::nonNull没有解决问题,因为非空车可以有name == null
      2017-01-09 11:41:45Z
    4. 当然@kiedysktos,但这不是我想在答案中显示的内容。但是,我接受你所说的并编辑答案:)
      2017-09-07 10:36:53Z
    5. 醇>

    您可以在单个过滤步骤中执行此操作:

     
    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());
    
        
    20
    2015-10-01 10:11:42Z
来源放置 这里