I have a stream and would like to check if all match a filter. If all match, return true
.
But, if the stream is empty, I'd like to return false
.
How can I do this?
Example code:
public boolean validate(Stream<Whatever> stream) {
// Problem: returns **true** if stream empty.
// How can **false** be returned if stream is empty?
return stream.allMatch(Whatever::someCheck);
}
You have to consume the stream to find out if it's empty. That's the point of Stream's semantics (laziness). To check that the stream is not empty you have to attempt to consume at least one element. At that point the stream has lost its "virginity" and cannot be consumed again from the start.
The boolean returned represents the value true if the string argument is not null and is equal, ignoring case, to the string "true" . Example: Boolean. parseBoolean("True") returns true . Example: Boolean.
Generating Streams With Java 8, Collection interface has two methods to generate a Stream. stream() − Returns a sequential stream considering collection as its source. parallelStream() − Returns a parallel Stream considering collection as its source.
Remember that loops use an imperative style and Streams a declarative style, so Streams are likely to be much easier to maintain. If you have a small list, loops perform better. If you have a huge list, a parallel stream will perform better.
You could use
public boolean validate(Stream<Whatever> stream) {
return stream.map(Whatever::someCheck).reduce(Boolean::logicalAnd).orElse(false);
}
which expresses the intent. We map each element to a boolean
value expressing whether it matches and reducing all of them with a logical and operation which will yield true
iff all of them were true
. reduce
will return an empty Optional
if there were no elements, which we map to false
using orElse(false)
, as intended.
The only disadvantage is that this is non short-circuiting, i.e. does not stop immediately at the first non-matching element.
A solution still supporting short-circuiting might be a bit more evolved:
public boolean validate(Stream<Whatever> stream) {
boolean parallel = stream.isParallel();
Spliterator<Whatever> sp = stream.spliterator();
if(sp.getExactSizeIfKnown() == 0) return false;
Stream.Builder<Whatever> b = Stream.builder();
if(!sp.tryAdvance(b)) return false;
return Stream.concat(b.build(), StreamSupport.stream(sp, parallel))
.allMatch(Whatever::someCheck);
}
This is a variant of Eugene’s answer, but it doesn’t loose characteristics or parallelism and might be a bit more efficient in general.
The following code will work (I tested it).
public static boolean validate(Stream<Whatever> stream) {
return stream.reduce((whatever1, whatever2) -> Whatever.someCheck(whatever1) ? whatever2 : whatever1)
.map(Whatever::someCheck).orElse(false);
}
How it works? We use reduce
operation to check that every element matches the predicate, if it fails, we keep returning the failing one (in ternary operation). At the end, we map the reduced Whatever
object to boolean, and if it's true: then all matched and this is not empty (orElse(false)
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With