use if-else statement in java-8 lambda expression

49,775

Solution 1

As a stream call chain is complex make two streams - avoiding the conditional branches.

String ncourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() != null)
   .map(EquivalentCourse::getNcourse)
   .map(x -> String.valueOf(x.getId()))
   .collect(Collectors.joining(", "));

String pastCourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() == null
          && equivalentCourse.getPastCourse() != null)
   .map(EquivalentCourse::getPastCourse)
   .map(x -> String.valueOf(x.getId()))
   .collect(Collectors.joining(", "));

This also is code focusing on the resulting two strings, with an efficient joining.

By the way, if this is for an SQL string, you may use a PreparedStatement with an Array.


Embellishment as commented by @Holger:

String ncourseIds = equivalentCourses.stream()
   .map(EquivalentCourse::getNcourse)
   .filter(Objects::nonNull)
   .map(NCourse::getId)
   .map(String::valueOf)
   .collect(Collectors.joining(", "));

String pastCourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() == null)
   .map(EquivalentCourse::getPastCourse)
   .filter(Objects::nonNull)
   .map(EquivalentCourse::getPastCourse)
   .map(PastCourse::getId)
   .map(String::valueOf)
   .collect(Collectors.joining(", "));

Solution 2

You could group by condition and then remap:

public void booleanGrouping() throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("ala");
    strings.add("ela");
    strings.add("jan");

    strings.stream()
            .collect(
                    Collectors.groupingBy(s -> s.endsWith("a")) // using function Obj -> Bool not predicate
            ).entrySet()
            .stream()
            .collect(
                    Collectors.toMap(
                            e -> e.getKey() ? "Present" : "Past",
                            e -> e.getValue().stream().collect(Collectors.joining(""))
                    )
            );
}

First stream group by condition, you should use equivalentCourse.getNcourse() != null second remap collections from value to string. You could introduce:

enum PresentPast{
    Present, Past
    PresentPast is(boolean v){
         return v ? Present : Past
    }
}

and change e -> e.getKey() ? "Present" : "Past" to enum based solution.

Edit:

Solution for else if:

public Map<Classifier, String> booleanGrouping() throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("ala");
    strings.add("ela");
    strings.add("jan");
    // our ifs:
    /*
        if(!string.endsWith("n")){
        }else if(string.startsWith("e")){}

        final map should contains two elements
        endsWithN -> ["jan"]
        startsWithE -> ["ela"]
        NOT_MATCH -> ["ala"]

     */
    return strings.stream()
            .collect(
                    Collectors.groupingBy(Classifier::apply) // using function Obj -> Bool not predicate
            ).entrySet()
            .stream()
            .collect(
                    Collectors.toMap(
                            e -> e.getKey(),
                            e -> e.getValue().stream().collect(Collectors.joining(""))
                    )
            );
}

enum Classifier implements Predicate<String> {
    ENDS_WITH_N {
        @Override
        public boolean test(String s) {
            return s.endsWith("n");
        }
    },
    STARTS_WITH_E {
        @Override
        public boolean test(String s) {
            return s.startsWith("e");
        }
    }, NOT_MATCH {
        @Override
        public boolean test(String s) {
            return false;
        }
    };

    public static Classifier apply(String s) {
        return Arrays.stream(Classifier.values())
                .filter(c -> c.test(s))
                .findFirst().orElse(NOT_MATCH);
    }
}
Share:
49,775
Shayan Mirzaee
Author by

Shayan Mirzaee

Updated on July 09, 2022

Comments

  • Shayan Mirzaee
    Shayan Mirzaee almost 2 years

    I have a for-statement in java-7 and it's work fine:

    Character cha = new Character(',');
    String ncourseIds = null;
    String pastCourseIds = null;
    for (EquivalentCourse equivalentCourse : equivalentCourses) {
      if(equivalentCourse.getNcourse() != null){
        ncourseIds += equivalentCourse.getNcourse().getId()+ ",";   
      } else if(equivalentCourse.getPastCourse() != null) {
        pastCourseIds +=equivalentCourse.getPastCourse().getId()+","; 
      }
    }
    if(!ncourseIds.isEmpty() &&cha.equals(ncourseIds.charAt(ncourseIds.length()-1))) {
      ncourseIds = ncourseIds.substring(0, ncourseIds.length()-1);
    }
    if(!pastCourseIds.isEmpty()&& cha.equals(pastCourseIds.charAt(pastCourseIds.length()-1))) {
      pastCourseIds = pastCourseIds.substring(0,pastCourseIds.length()-1);
    }
    

    Now I want to convert my code to Stream & collect in java-8, I implement half of my business about filter not null Ncourse:

    equivalentCourses.stream().filter(obj -> obj.getNcourse() != null )
                     .map(obj -> obj.getNcourse().getId()).collect(Collectors.joining(",")); 
    

    but I don't know to implement it's else-statement. any help?

  • Cuga
    Cuga about 7 years
    Nice use of the double-colon!
  • Holger
    Holger about 7 years
    You can simplify by changing the order. First stream op: .map(EquivalentCourse::getNcourse) .filter(Objects::nonNull), second stream op: .filter(equivalentCourse -> equivalentCourse.getNcourse() == null) .map(EquivalentCourse::getPastCourse) .filter(Objects::nonNull).
  • MBec
    MBec about 7 years
    That is good solution only for if-else statement, but question is about else-if statement. In that case you need to perform two stream operation.
  • Koziołek
    Koziołek about 7 years
    I see :) I will fix that (you need introduce a little bit different condition) when I back to my main PC :D
  • Joop Eggen
    Joop Eggen about 7 years
    @Holger you are right, and also the getId could be improved with some class knowledge
  • Gibbs
    Gibbs about 4 years
    @JoopEggen If equivalentCourses has huge number of elements, this is inefficient. Isn't? If so, is there any way to make it efficiently?
  • Joop Eggen
    Joop Eggen about 4 years
    @Gibbs no, neither in O-complexity, neither in speed or space usage. In an old for-loop one could hold two StringBuilders and append to them in one loop and an internal if-else for appending to either StringBuilder. Making that two for-loops for each StringBuilder would be somewhat the same.
  • Gibbs
    Gibbs about 4 years
    Thanks @JoopEggen I will give a try soon