使用 Java8 Streams 减少 if-else 语句,同时过滤多个条件

Reduce if-else statements with Java8 Streams while filtering multiple conditions

提问人:turing23 提问时间:11/4/2023 最后编辑:user207421turing23 更新时间:11/6/2023 访问量:94

问:

我从同行那里得到了评论,说我需要减少在代码中使用多个 If-else 块,而是使用命令式编程技术来实现相同的功能

背景我有一个事件列表,我需要根据几个条件返回一个事件对象。对于 SOP 事件和 SOP 确认事件,列表的大小可以是 2 或 3,对于非 SOP 确认事件,大小为 2,但事件类型不同,最后是大小为 1 的单个事件。

//All Required Predicates

//SOP Special Event
if(eventList.size() >1 && results.getAcknowledgeUid().isEmpty()){
       event = eventList.stream().filter(isOriginalEvent.and(isSOPEvent).and(isSOPSpecialEvent))
                                 .findFirst().orElse(null);
} 
else if (eventList.size() >1 && !results.getAcknowledgeUid().isEmpty()) {
       // SOP Acnknowledge Event
       if("SOP".equalsIgnoreCase(eventList.get(0).getEventType())) {
           event = eventList.stream().filter(isAcknowledgeEvent)
                                     .findFirst().orElse(null);
       }
       // Non SOP Acnknowledge Event
       List<event> eventAcnknowledgeList = repository.findEventByUid(results.getAcnknowledgeUid);
       event = eventAcnknowledgeList.stream().filter(isAcnknowledgeEvent)
                                       .findFirst().orElse(null);
}
// Single Event
else if (eventList.size() >0) {
       event = eventList.stream().filter(isOriginalEvent).findFirst().orElse(null);
}

我将 if else 块中的所有条件都移动到谓词中,它现在看起来很紧凑。但我仍然无法减少 if-else 链。我考虑过使用三元运算符来合并第二个和第三个块,但如果我这样做,代码看起来很笨拙。 我也无法执行以下操作。

Predicate<List<Event>> isMoreThanTwoEvents = event -> eventList.size() > 1;

 event = eventList.stream().filter(isAcknowledgeEvent.and(isSOPEvent).and(isMoreThanTwoEvents))
                                 .findFirst().orElse(null);

这让我在IDE中出现错误

必需类型谓词<?超级活动> 提供的谓词<列表>

  1. 如何减少 If-Else 链接?
  2. 如何筛选集合中流中超出该集合范围的数据?
  3. 这个问题有没有更好或更优雅的解决方案?
java if 语句 java-8 java

评论


答:

0赞 GreyBeardedGeek 11/5/2023 #1

一种简单的方法是使用提前回报。

例如

if(foo) {
 return "foo";
}

if(bar) {
 return "bar";
}

etc...
2赞 Bohemian 11/6/2023 #2

流和谓词不是灵丹妙药,普通 s 也没有错。if

小规模的重构,主要是删除冗余条件,产生:

if (eventList.size() > 1) { //SOP Special Event
    if (results.getAcknowledgeUid().isEmpty()) {
        event = eventList.stream().filter(isOriginalEvent.and(isSOPEvent).and(isSOPSpecialEvent))
                .findFirst().orElse(null);
    } else {
        if ("SOP".equalsIgnoreCase(eventList.get(0).getEventType())) { // SOP Acnknowledge Event
            event = eventList.stream().filter(isAcknowledgeEvent)
                    .findFirst().orElse(null);
        } else { // Non SOP Acnknowledge Event
            event = eventAcnknowledgeList = repository.findEventByUid(results.getAcnknowledgeUid)
                    .stream().filter(isAcnknowledgeEvent)
                    .findFirst().orElse(null);
    }
} else { // Single Event
    event = eventList.stream().filter(isOriginalEvent).findFirst().orElse(null);
}

具有良好的可读性。

1赞 Jean-Baptiste Yunès 11/6/2023 #3

至少那个块是错误的:

   // SOP Acnknowledge Event
   if("SOP".equalsIgnoreCase(eventList.get(0).getEventType())) {
       event = eventList.stream().filter(isAcknowledgeEvent)
                                 .findFirst().orElse(null);
   }
   // Non SOP Acnknowledge Event
   List<event> eventAcnknowledgeList = repository.findEventByUid(results.getAcnknowledgeUid);
   event = eventAcnknowledgeList.stream().filter(isAcnknowledgeEvent)
                                   .findFirst().orElse(null);

还有一个(可能)缺少其他东西,不是吗?

   // SOP Acnknowledge Event
   if ("SOP".equalsIgnoreCase(eventList.get(0).getEventType())) {
       event = eventList.stream().filter(isAcknowledgeEvent)
                                 .findFirst().orElse(null);
   } else {
       // Non SOP Acnknowledge Event
       List<event> eventAcnknowledgeList = repository.findEventByUid(results.getAcnknowledgeUid);
       event = eventAcnknowledgeList.stream().filter(isAcnknowledgeEvent)
                                   .findFirst().orElse(null);
   }

如果是;

if (n>1 && cond)
else if (n>1 && !cond)
else if (n>0)

至少测试两次是多余的。你可以这样写:cond

if (n>1)
    if (cond)
    else
else if (n>0)

如果始终为 1、2 或 3,则可能会删除最后一个测试:n

if (n>1)
    if (cond)
    else
else

这给了:

if (eventList.size()>1) {
    if (results.getAcknowledgeUid().isEmpty()) {
        event = eventList.stream().filter(isOriginalEvent.and(isSOPEvent).and(isSOPSpecialEvent))
                                 .findFirst().orElse(null);
    } else { 
       // SOP Acnknowledge Event
       if("SOP".equalsIgnoreCase(eventList.get(0).getEventType())) {
           event = eventList.stream().filter(isAcknowledgeEvent)
                                     .findFirst().orElse(null);
       } else {
       // Non SOP Acnknowledge Event
           List<event> eventAcnknowledgeList = repository.findEventByUid(results.getAcnknowledgeUid);
           event = eventAcnknowledgeList.stream().filter(isAcnknowledgeEvent)
                                       .findFirst().orElse(null);
       }
else {
       event = eventList.stream().filter(isOriginalEvent).findFirst().orElse(null);
}

您还可以分解对 findFirst.orElse 和过滤器的调用:

Stream<SOMETYPE> s = null;
Predicate<SOMETYPE> f = null
if (eventList.size()>1) {
    if (results.getAcknowledgeUid().isEmpty()) {
        s = eventList.stream();
        f = isOriginalEvent.and(isSOPEvent).and(isSOPSpecialEvent);
    } else { 
       if("SOP".equalsIgnoreCase(eventList.get(0).getEventType())) {
           s = eventList.stream()
       } else {
           s = repository.findEventByUid(results.getAcnknowledgeUid).stream()
       }
       f = filter(isAcnknowledgeEvent);
else {
       s =  eventList.stream();
       f = isOriginalEvent;
}
event = s.filter(f).findFirst().orElse(null);

评论

0赞 turing23 11/7/2023
非常感谢你@JeanBaptiste 即使我正在嵌套 if else 块,我也希望我的评论能通过,因为这非常简洁明了。这也将帮助我将来更好地设计我的代码。