Search code examples
javaif-statementjava-8java-stream

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


I got a review comment from my peers that i need to reduce the use of multiple If-else blocks in my code and instead use imperative programming techniques to achieve the same functionality

Background I have a List of Events and i need to return an event object based on few conditions.For an SOP Event and SOP Acknowledge Event the size of the list could be 2 or 3, for a Non-Sop Acknowledge event the size is 2 but event type is different, finally there is a single event where the size is 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);
}

I moved all my conditions within in the if else blocks to predicates and it's looking compact right now. But i'm still unable to reduce the if-else chain. I considered using ternary operator to merge the second and third blocks, but the code is looking clumsy if i did that. i'm unable to do the following as well.

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

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

which gives me an error in the IDE

Required type Predicate <? super Event> Provided Predicate <List>

  1. How do i reduce the If-Else Chaining?
  2. How do i filter data in Streams within a Collection that are outside the scope of that collection?
  3. Is there a better or elegant solution to this problem?

Solution

  • At least that block is wrong:

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

    there is a (probably) missing else, isn't it?

       // 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);
       }
    

    The ifs are;

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

    at least testing cond twice is redundant. You may write it:

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

    and if n is always 1, 2 or 3 then the last test may be removed:

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

    which gives:

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

    You may also factorize the calls to findFirst.orElse and filters:

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