use if-else statement in java-8 lambda expression
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);
}
}
Shayan Mirzaee
Updated on July 09, 2022Comments
-
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 nullNcourse
: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 about 7 yearsNice use of the double-colon!
-
Holger about 7 yearsYou 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 about 7 yearsThat is good solution only for
if-else
statement, but question is aboutelse-if
statement. In that case you need to perform two stream operation. -
Koziołek about 7 yearsI see :) I will fix that (you need introduce a little bit different condition) when I back to my main PC :D
-
Joop Eggen about 7 years@Holger you are right, and also the getId could be improved with some class knowledge
-
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 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 about 4 yearsThanks @JoopEggen I will give a try soon