Reputation: 1072
In Java 8, is there a way to apply the filter on a stream based on a condition,
example
I have this stream
if (isAccessDisplayEnabled) {
src = (List < Source > ) sourceMeta.getAllSources.parallelStream()
.filter(k - > isAccessDisplayEnabled((Source) k))
.filter(k - > containsAll((Source) k, substrings, searchString))
.collect(Collectors.toList());
} else {
src = (List < Source > ) sourceMeta.getAllSources.parallelStream()
.filter(k - > containsAll((Source) k, substrings, searchString))
.collect(Collectors.toList());
}
I am adding the filter
.filter(k - > isAccessDisplayEnabled((Source) k)))
on the stream based on the if-else condition. Is there a way to avoid that if-else, since if there are more filters coming up,then it will be hard to maintain.
Please let me know
Upvotes: 43
Views: 96632
Reputation: 5372
A totally different approach compared to the other anwsers: You can split the fluent syntax of java stream to different parts, and do whatever you need to construct you own perfect pipeline. You can save any part of the stream definition in variables, it is not executed before you call the collect method.
Unverified code (you'll have to fix the type declaration):
Stream<whatever> unfinishedStream = sourceMeta.getAllSources.parallelStream();
if (isAccessDisplayEnabled) {
unfinishedStream = unfinishedStream.filter(k - > isAccessDisplayEnabled((Source) k));
}
src = (List < Source > ) unfinishedStream
.filter(k - > containsAll((Source) k, substrings, searchString))
.collect(Collectors.toList());
At first, this looks like the most optimal solution. But I heard that java does quite extreme compile-time stream optimization, by transforming them to simple loops. If you start constructing your pipeline dynamically as shown above, Java will likely fall back to simply executing what you defined, with a lot of method calls and internal structure. But I didn't do any benchmarks.
We use this kind of programming a lot for dynamic SQL statements with configurable filters, but there's no such compile-time optimization.
Upvotes: 2
Reputation: 298113
One way to do it is
Stream<Source> stream = sourceMeta.getAllSources.parallelStream().map(x -> (Source)x);
if(isAccessDisplayEnabled) stream = stream.filter(s -> isAccessDisplayEnabled(s));
src = stream.filter(s - > containsAll(s, substrings, searchString))
.collect(Collectors.toList());
another
src = sourceMeta.getAllSources.parallelStream().map(x -> (Source)x)
.filter(isAccessDisplayEnabled? s - > isAccessDisplayEnabled(s): s -> true)
.filter(s - > containsAll(s, substrings, searchString))
.collect(Collectors.toList());
In either case, note how performing one type cast at the beginning simplifies the entire stream pipline.
Both solutions avoid re-evaluating isAccessDisplayEnabled
for every stream element, however, the second relies on the JVM’s capability of inlining s -> true
when this code turns out to be performance critical.
Upvotes: 53
Reputation: 3169
Your condition has the same name as your method. I'm going to assume you meant for those to be different, so let's say it was this:
if (someCondition) {
src = (List < Source > ) sourceMeta.getAllSources.parallelStream()
.filter(k - > isAccessDisplayEnabled((Source) k))
.filter(k - > containsAll((Source) k, substrings, searchString))
.collect(Collectors.toList());
} else {
src = (List < Source > ) sourceMeta.getAllSources.parallelStream()
.filter(k - > containsAll((Source) k, substrings, searchString))
.collect(Collectors.toList());
}
If you want to remove the if/else, you can instead perform the check in the first filter:
src = (List < Source > ) sourceMeta.getAllSources.parallelStream()
.filter(k - > !someCondition || isAccessDisplayEnabled((Source) k))
.filter(k - > containsAll((Source) k, substrings, searchString))
.collect(Collectors.toList());
In the else case, you take everything and remove the isAccessDisplayEnabled() method call, so the condition is effectively "if someCondition is false or isAccessDisplayEnabled(k)". If someCondition comes out false, then the isAccessDisplayEnabled() check is skipped.
Upvotes: 5