I want to use Stream.allMatch()
, but I need a false
when the stream is empty.
public static void main (String[] args) throws java.lang.Exception
{
System.out.println(testMethod(Stream.empty())); // <- expected false (but is true)
System.out.println(testMethod(Stream.of("match", "match"))); // <- expected true
System.out.println(testMethod(Stream.of("match", "no match"))); // <- expected false
}
private static boolean testMethod(Stream<String> stream) {
return stream.allMatch(text -> "match".equals(text));
}
I don't want to use ...
.toList()
, because I want How does short-circuit work for Java 8 Streams?.reduce()
, because How does short-circuit work for Java 8 Streams?I guess, that I have to use noMatch()
, but I didn't get the negation to work correclty.
private static boolean testMethod(Stream<String> stream) {
// my guess, but the results are wrong
return !stream.noneMatch(text -> !"match".equals(text));
}
This is not a duplicate of How to return false for an empty list if using Stream.allMatch()? because I use Stream
s and not List
s.
It's about status-collecting. Let's simply this as a download-status indicator for the user. (Not my real use-case, but it is close).
I have a table downloads
which looks like this
userId | download_name | download_status | data |
---|---|---|---|
1 | download 1 | loading | null |
2 | download 2 | ready | 0x4545475 |
I can't change the tables and I'm limited because it is a huge project (sadly not possible to refactor the world).
Anyways, I want to show the user an indicator about his downloads. The indicator should be only visible, if all downloads are ready. But, if there no downloads yet, then the user should not see the indicator.
I have a given repository-method Stream<Downloads> getDownloadsForUser()
. The short-circuit is important to reduce the load.
Java's Stream
design doesn't make it easy to check in a single pass whether the stream is empty and whether all elements match a given predicate. You can use a local variable to keep track of count (but it must be effectively final, therefore you would have to use a well-known hack such as a 1-element array). This way, you can retain Stream's short-circuiting behaviour while also checking if the stream is empty.
However, it doesn't make sense in pure mathematics/logic terms to regard an empty stream as not having elements that all match a predicate. This is the vacuous truth concept.
/**
* DO NOT USE. This uses the wrong logic: see
* <a href="https://en.wikipedia.org/wiki/Vacuous_truth#In_computer_programming">vacuous truth</a>.
*/
private static boolean allMatchExceptReturnFalseIfEmpty(Stream<String> stream) {
boolean[] empty = { true };
return stream.allMatch(text -> { empty[0] = false; return "match".equals(text); }) && !empty[0];
}
The above method treats the empty stream as a special value that returns the opposite result. In many situations, it may be better to take some special handling in such cases, and that can be done if the method throws an exception:
/**
* Better. Checks that all elements match, at the same time checking that the stream is not empty.
*/
private static boolean allMatchNonEmptyStream(Stream<String> stream) {
boolean[] empty = { true };
boolean result = stream.allMatch(text -> { empty[0] = false; return "match".equals(text); });
if (empty[0])
throw new IllegalArgumentException("Stream must not be empty");
return result;
}
Another way of looking at this problem is that you want a three-state result:
enum MatchResult { EMPTY, ALL_MATCH, SOME_DONT_MATCH }
private static MatchResult allMatchThreeState(Stream<String> stream) {
boolean[] empty = { true };
boolean allMatch = stream.allMatch(text -> { empty[0] = false; return "match".equals(text); });
return (empty[0]) ? MatchResult.EMPTY : allMatch ? MatchResult.ALL_MATCH : MatchResult.SOME_DONT_MATCH;
}
In your case (following the update to your question), you might want to make use of this 3-state value to show, for example, (1) no indicator; (2) "download in progress"; and (3) "download complete". Even if you don't want to have 3 different indicator states right now, having this 3-state method result will give you better flexibility.