I would like to have the following logic: (i know it doesn't work because it consumes the stream more than once). but i am not sure how to achieve it.
Stream<ByteBuffer> buffers = super.getBuffers().stream();
if (buffers.allMatch(b -> b.position() > 0)) {
return OutgoingMessageStatus.FULLY_SENT;
} else if (buffers.noneMatch(b -> b.position() > 0)) {
return OutgoingMessageStatus.WAS_NOT_SENT;
} else {
return OutgoingMessageStatus.PARTIALLY_SENT;
}
How can I do that?
anyMatch() returns true if any of the elements in a stream matches the given predicate. If the stream is empty or if there's no matching element, it returns false . allMatch() returns true only if ALL elements in the stream match the given predicate.
Stream anyMatch(Predicate predicate) returns whether any elements of this stream match the provided predicate. It may not evaluate the predicate on all elements if not necessary for determining the result. This is a short-circuiting terminal operation.
Since the result of super.getBuffers()
is List<ByteBuffer>
, you can iterate over it twice.
List<ByteBuffer> buffers = super.getBuffers();
if (buffers.stream().allMatch(b -> b.position() > 0)) {
return OutgoingMessageStatus.FULLY_SENT;
} else if (buffers.stream().noneMatch(b -> b.position() > 0)) {
return OutgoingMessageStatus.WAS_NOT_SENT;
} else {
return OutgoingMessageStatus.PARTIALLY_SENT;
}
Note that this still doesn’t need iterating over all elements in all cases. allMatch
returns as soon as it encounters a non-matching element, noneMatch
returns as soon as it encounters a matching element. So in the PARTIALLY_SENT
case, it is possible that it got the conclusion without looking at all elements.
An alternative is
List<ByteBuffer> buffers = super.getBuffers();
if(buffers.isEmpty()) return OutgoingMessageStatus.FULLY_SENT;
Predicate<ByteBuffer> p = b -> b.position() > 0;
boolean sent = p.test(buffers.get(0));
if(!sent) p = p.negate();
return buffers.stream().skip(1).allMatch(p)? sent?
OutgoingMessageStatus.FULLY_SENT:
OutgoingMessageStatus.WAS_NOT_SENT:
OutgoingMessageStatus.PARTIALLY_SENT;
}
The status of the first element determines which condition we have to check. As soon as there is a contradicting element, allMatch
returns immediately and we have a PARTIALLY_SENT
situation. Otherwise, all elements match like the first which implies either “all sent” or “none sent”.
The pre-check for an empty list produces the same behavior as the original code and ensures that get(0)
never breaks.
If you really have a Stream instead of a source that you can iterate multiple times, there is no simple short-cutting solutions, as that would require a stateful predicate. There are, however, simple solutions processing all elements.
Map<Boolean,Long> result=getBuffers().stream()
.collect(Collectors.partitioningBy(b -> b.position() > 0, Collectors.counting()));
return
result.getOrDefault(false, 0L)==0?
OutgoingMessageStatus.FULLY_SENT:
result.getOrDefault(true, 0L)==0?
OutgoingMessageStatus.WAS_NOT_SENT:
OutgoingMessageStatus.PARTIALLY_SENT;
or
return super.getBuffers().stream()
.map(b -> b.position() > 0?
OutgoingMessageStatus.FULLY_SENT: OutgoingMessageStatus.WAS_NOT_SENT)
.reduce((a,b) -> a==b? a: OutgoingMessageStatus.PARTIALLY_SENT)
.orElse(OutgoingMessageStatus.FULLY_SENT);
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