【问题标题】:How to use streams for the logic with multiple conditional checks? [closed]如何将流用于具有多个条件检查的逻辑? [关闭]
【发布时间】:2020-12-08 16:19:31
【问题描述】:

我正在学习 Java 11,并想使用 Java 11 编写以下逻辑块。任何输入都会有所帮助。由于它有许多条件检查,我们可以使用 lambda 或流来实现以下逻辑块。

@Data
class MyDetails{
    private String name;
    private String status;
    private Integer spreadValue;
    private Object value;
    ...
}
public List<MyDetails> returnValidList(Collection<MyDetails> myDetails){
    for (MyDetails myDetail : myDetails){
        if (myDetail !=null && myDetail.getValue()!=null){
            if (myDetail.getSpreadValue()==3 || myDetail.getSpreadValue()==4){
                if (myDetail.getName().equalsIgnoreCase("AUTO") || myDetail.getName().equalsIgnoreCase("HOME")){
                   result.add(myDetail);
                } else {
                   result.add(myDetail);
                }
            }
        }
        return result;
    }
}

我尝试了以下代码,但列表大小为零,预期列表大小为 17。任何建议以更正以下 sn-p。

List<MyDetails> result = myDetails.stream()
    .filter(Objects::nonNull)
    .filter(obj -> Objects.nonNull(obj.getValue()))
    .filter(obj -> obj.getSpreadValue() == 3 || obj.getSpreadValue() == 4)
    .collect(Collectors.toList());

【问题讨论】:

  • 提供类结构会有很大帮助。
  • 编辑了帖子,它是一个普通的实用程序类。 @NikolasCharalambidis
  • 我说的是MyDetails 类。实用程序类将如何帮助获得答案?
  • 如果你最终将result.add(myDetail); 作为两者的唯一部分,你为什么还需要最里面的if..else
  • @Naman - 是的,不需要内部 if(..) 块。我已经包含了我在上面的帖子中尝试过的代码,但列表大小是 0 而不是 17。

标签: java java-stream java-11


【解决方案1】:

您唯一能做的就是通过 Stream API 链接 filter 调用。

List<MyDetails> result = myDetails.stream()
    .filter(Objects::nonNull)
    .filter(obj -> Objects.nonNull(obj.getValue()))
    .filter(obj -> obj.getSpreadValue() == 3 || obj.getSpreadValue() == 4)
    .filter(obj -> obj.getName().equalsIgnoreCase("AUTO") || obj.getName().equalsIgnoreCase("HOME"))
    .collect(Collectors.toList());

以更复杂的方式,您可能希望将条件提取到单独的变量或方法中(返回 Predicate&lt;MyDetails&gt;。但是,在高级和可配置过滤的情况下,我建议迭代此类谓词的集合可以在申请前先过滤:

// Predicate list
List<Predicate<MyDetails>> predicates = List.of(
    Objects::nonNull, // should be always first
    obj-> Objects.nonNull(obj.getValue()),
    obj-> obj.getSpreadValue() == 3 || obj.getSpreadValue() == 4,
    obj-> obj.getName().equalsIgnoreCase("AUTO") || obj.getName().equalsIgnoreCase("HOME")
);

// Reduction using AND. If no predicate is qualified, 
// ... a predicate that everything passes through is returned (identity)
Predicate<MyDetails> predicate = predicates.stream()
    .reduce(obj -> true, Predicate::and);

// Apply the predicate
List<MyDetails> result = myDetails.stream()
    .filter(predicate)
    .collect(Collectors.toList());

关于实现的说明:

  • 在这种情况下,Stream API 没有任何改进,除非您需要可配置或高级过滤。
  • 如果您想拥有可配置的谓词,请使用 LinkedHashMap 并按键过滤不需要的谓词。

只要你的代码看起来很不完整,就会进行一些代码审查(尽管我已尽力格式化并使其清晰):

  • 您在方法中错过了另一个 return
  • MyDetails 定义中缺少 private Something value;
  • List&lt;MyDetails&gt; 在方法中未定义(记住您调用了getValue())。
  • obj.getSpreadValue() == 3 || obj.getSpreadValue() == 4)obj.getName().equalsIgnoreCase("AUTO") || obj.getName().equalsIgnoreCase("HOME") 是重构的主题。我建议使用HashSetSet::contains
  • AUTOHOME 名称的条件检查无关紧要,因为两个 分支都会将项目添加到列表中。

【讨论】:

  • 我们可以使用 Set::contains 以及您在答案开头提到的 stream() 和过滤器。我需要对 AUTO 和 HOME 进行条件检查。感谢所有输入。
  • 我尝试了您上面建议的两种实现,列表大小为零,而与我的实际代码一样,列表大小为 17。
  • 当使用上述答案中所述的流和过滤器时,我得到的列表大小为 0,有输入吗?
  • @user3633028 两个代码的结果可能不同,如果你能澄清this comment.. 另一个方面是equalsIgnoreCase 不能直接转换为contains 在元素上的 Set 除非当然它详尽无遗或输入映射到特定情况。
  • @Nikolas 具有身份的reduce 会比orElse 更好。
猜你喜欢
  • 1970-01-01
  • 2020-04-15
  • 2017-04-13
  • 1970-01-01
  • 2017-12-10
  • 1970-01-01
  • 1970-01-01
  • 2021-09-22
  • 2011-09-13
相关资源
最近更新 更多