43

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

3 Answers 3

54

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.

Sign up to request clarification or add additional context in comments.

8 Comments

I am not able to understand this line, isAccessDisplayEnabled? s -> true: s - > isAccessDisplayEnabled(s), please can you explain a bit more or to a blog that explains it.
Try reading it as isAccessDisplayEnabled? (s -> true): (s -> isAccessDisplayEnabled(s)). If isAccessDisplayEnabled is true, use the lambda expression s -> true, which is effectively like having no filter, otherwise, use s - > isAccessDisplayEnabled(s). It’s a combination of the ternary operator with two alternative lambda expressions.
@Holder : ok for ternary but order is wrong , no ? I guess if you have a boolean isAccessDisplayEnabled then you want to filter, otherwise if false you do not filter. ` isAccessDisplayEnabled? (s -> isAccessDisplayEnabled(s)) : (s -> true) `
Why not to use filter(!isAccessDisplayEnabled || isAccessDisplayEnabled(s)) ?
@Cherry the syntax would be filter(s -> !isAccessDisplayEnabled || isAccessDisplayEnabled(s)) and it would work, but as said in the answer, both solutions [of the answer] avoid re-evaluating isAccessDisplayEnabled for every stream element. Since isAccessDisplayEnabled doesn’t change throughout the entire operation, it would be a waste of CPU cycles to check this over and over again.
|
5

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.

4 Comments

…but someCondition may get reevaluated for every element.
A variable and a method can have the same name in Java. Java is a Lisp 2 in that sense. ;)
@DavidConrad I'm sure that's true, however I don't think he meant it that way. I just changed the variable name to clear things up.
Yes, you are correct, i miss typed variable and method have different names
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.