I just came across a question when using a List
and its stream()
method. While I know how to use them, I’m not quite sure about when to use them.
For example, I have a list, containing various paths to different locations. Now, I’d like to check whether a single, given path contains any of the paths specified in the list. I’d like to return a boolean
based on whether or not the condition was met.
This of course, is not a hard task per se. But I wonder whether I should use streams, or a for(-each) loop.
The List
private static final List<String> EXCLUDE_PATHS = Arrays.asList( "my/path/one", "my/path/two" );
Example using Stream:
private boolean isExcluded(String path) { return EXCLUDE_PATHS.stream() .map(String::toLowerCase) .filter(path::contains) .collect(Collectors.toList()) .size() > 0; }
Example using for-each loop:
private boolean isExcluded(String path){ for (String excludePath : EXCLUDE_PATHS) { if (path.contains(excludePath.toLowerCase())) { return true; } } return false; }
Note that the path
parameter is always lowercase.
My first guess is that the for-each approach is faster, because the loop would return immediately, if the condition is met. Whereas the stream would still loop over all list entries in order to complete filtering.
Is my assumption correct? If so, why (or rather when) would I use stream()
then?
Advertisement
Answer
Your assumption is correct. Your stream implementation is slower than the for-loop.
This stream usage should be as fast as the for-loop though:
EXCLUDE_PATHS.stream() .map(String::toLowerCase) .anyMatch(path::contains);
This iterates through the items, applying String::toLowerCase
and the filter to the items one-by-one and terminating at the first item that matches.
Both collect()
& anyMatch()
are terminal operations. anyMatch()
exits at the first found item, though, while collect()
requires all items to be processed.