【问题标题】:multiple filter using lambda java使用 lambda java 的多重过滤器
【发布时间】:2017-10-03 19:59:30
【问题描述】:

我正在尝试像这样过滤 java 集合:

filtered = products.stream()
                .filter((product) ->size!=null&& 
                 product.getSize().equalsIgnoreCase(size))
                .filter((product) ->firmness!=null  && 
                 product.getFirmness().equalsIgnoreCase(firmness))
                .collect(Collectors.toList());

在这个例子中,我有两个变量要过滤 - 尺寸和硬度。此变量是可选的,可以为空。 因此,如果我发送两个非空参数,则代码可以正常工作并且过滤良好,但是当我只发送一个参数并将其他参数设置为空时 - 它不起作用。我需要我的集合被非空值过滤。因此,如果一个参数为空,另一个不是,则集合必须通过非空值过滤。我是怎么做到的?

【问题讨论】:

  • @JoeC 哦该死的,这是一个有用的链接!!
  • 只用一个过滤器。

标签: java lambda filter java-8


【解决方案1】:

&& 要求它不为空。用|| 反转条件,例如,

size == null || product.getSize().equalsIgnoreCase(size)

如果你想避免对每个元素进行 null 检查,你可以将整个 lambda 表达式放在一个三元表达式中:

.filter(size == null ? p -> true : p -> p.getSize().equalsIgnoreCase(size))

【讨论】:

  • 因为这是一个捕获Predicate,它将为源的每个元素创建一个新实例。另一方面,在流操作发生之前计算谓词......我喜欢这种方法
  • @Eugene 你错了。
  • 对我来说可能为时已晚,但你不是一直在捕捉sizefirmness 吗?
  • 在创建谓词时捕获一次。
【解决方案2】:

类似的东西,不过我还没有编译过。
您甚至可以在开始管道处理之前计算您的 Predicate

static  Predicate<Product> predicate(String size, String firmness) {
     if(size != null && firmness != null){
         return p -> p.getSize().equalsIgnoreCase(size) 
                && p.getFirmness().equalsIgnoreCase(firmness);
     } else if(size != null){
         return p -> p.getSize().equalsIgnoreCase(size); 
     } else if(firmness != null){
         return p -> p.getFirmness().equalsIgnoreCase(firmness);
     } else {
         return p -> false;
     }
 }

【讨论】:

  • 如果firmnesssizenull,你会得到错误的过滤,但这是因为这个答案真正需要的是当它们都是null 时的谓词。
  • @Oleg 现在我已经编辑了我不太喜欢这里的冗长:) 仍然感谢您纠正我
  • 我实际上更喜欢使用一个过滤器,我想这是一个偏好问题。此外,如果我正确理解了这个问题,else 应该是true
【解决方案3】:

还可以查看来自 BlobCity java-commons 的 CollectionUtil.retainIf(collection, predicate) https://blog.blobcity.com/2018/07/15/retainif-and-removeif-for-java-collections-blobcity/

CollectionUtil.retainIf(products, product -> product.getSize().equalsIgnoreCase(size));
CollectionUtil.retainIf(products, product -> product.getFirmness().equalsIgnoreCase(firmness));

每次调用都会减少原始列表以仅保留那些满足谓词条件的值。如果需要,可以在谓词中添加空检查。

【讨论】:

    【解决方案4】:

    更新。感谢 shmosel 的回答,在这个 lambda 示例中使用三元运算有更好的方法:

    filtered = products.stream()
    .filter( size == null ? p -> true : p -> p.getSize().equalsIgnoreCase(size) )
    .filter( firmness == null ? p -> true : p -> product.getFirmness().equalsIgnoreCase(firmness) )
    .collect( Collectors.toList() );
    

    正如 Holger 提到的,将空值检查移出 lambda 表达式将避免对每个 product 重复检查 null 并避免不必要的捕获或 sizefirmness null,这有助于根据 @ 的性能987654321@。

    这是原来的方法:

    filtered = products.stream()
    .filter( (product) -> size != null ? product.getSize().equalsIgnoreCase(size) : true )
    .filter( (product) -> firmness != null ? product.getFirmness().equalsIgnoreCase(firmness) : true )
    .collect( Collectors.toList() );
    

    【讨论】:

    • 太棒了。我之前正在尝试使用三元运算符。但是我的错误是第二种情况是错误的,而不是像您的示例中那样“真实”。我已将其更改为 true,并且现在可以使用。谢谢!
    • 三元表达式永远不应该返回布尔值。
    • @shmosel 你能以此为基础吗? (不争论,好奇)在这种情况下我觉得很好。
    • @Oleg 您始终可以使用逻辑运算符来产生相同的结果。例如,请参阅我的答案。
    • @shmosel 我仍然不确定为什么必须遵循“三元表达式永远不应该返回布尔文字”。规则。
    猜你喜欢
    • 2014-07-29
    • 1970-01-01
    • 2022-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-02
    • 2014-09-06
    相关资源
    最近更新 更多