Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prioritize stream filter functions in Java

I am seeking for an option to filter in-streams but using priorities.

The following is the pseudo code:

results.stream().filter(prio1).ifNotFound(filter(prio2)).collect(toList())

The list of results shall be filtered by first criteria called "prio1" and if there ain't no match found the second filter shall be applied to try filter on second criteria called prio2 and then the results shall be collected

How do I achive this in Java 8 using streams?

I am looking for a one-liner in stream.

like image 747
Ckkn Avatar asked Jun 30 '26 18:06

Ckkn


1 Answers

You will need to stream() your results twice, but the following should work as a one-liner:

results.stream().filter(results.stream().anyMatch(prio1) ? prio1 : prio2).collect(Collectors.toList());

(Credit to flakes for first publishing a multiple-liner using a similar strategy.)

Edit: Since some excellent new answers have come to light, I thought I would offer a short defense of this multiple-stream / anyMatch strategy making reference to certain other parts of this thread:

  • As pointed out by eckes, anyMatch is optimized to return early and thus minimal time is spent reading the extra stream (especially for the case where prio1 is likely to match). In fact, anyMatch will only read the whole stream in the fallback (prio2) case, so for the average run you are only iterating through one-and-a-fraction list lengths.

  • Using the Collectors.groupingBy(...) method constructs a Map and two Lists in every case, while the approach above only creates at most a single List. The difference in memory overhead here will become quite significant as the size of results increases. The grouping is done for the entire stream, so even if the very first element happens to pass prio1, every element has to be checked against prio1.or(prio2) and then against prio1 once more.

  • groupingBy does not account for the case where prio1 and prio2 are not mutually exclusive. If prio2.test(e) can return true for some e which passes prio1, such elements will be missing within the fallback prio2 list. Using anyMatch and one filter at a time avoids this problem.

  • The line length and complexity of the above method seems far more manageable to me.

like image 122
gyre Avatar answered Jul 03 '26 06:07

gyre