Combine allMatch, noneMatch and anyMatch on a single stream
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);
You can use filter()
, and then count the number of elements that pass it :
Stream<ByteBuffer> buffers = super.getBuffers().stream();
int matches = buffers.filter(b -> b.position() > 0).count();
if (matches == super.getBuffers().size()) {
return OutgoingMessageStatus.FULLY_SENT;
} else if (matches == 0) {
return OutgoingMessageStatus.WAS_NOT_SENT;
} else {
return OutgoingMessageStatus.PARTIALLY_SENT;
}
This assumes that the data source of the Stream
(super.getBuffers()
) has a size()
method. If it doesn't, you can count the total number of ByteBuffer
s using an additional variable (less elegant, I know) :
int[] total = {0};
int matches = buffers.filter(b -> {total[0]++; return b.position() > 0;}).count();
if (matches == total[0]) {
return OutgoingMessageStatus.FULLY_SENT;
} else if (matches == 0) {
return OutgoingMessageStatus.WAS_NOT_SENT;
} else {
return OutgoingMessageStatus.PARTIALLY_SENT;
}
The disadvantage of that approach is that it doesn't fail fast when when only some of the elements pass the filter (i.e. output should be OutgoingMessageStatus.PARTIALLY_SENT
). Perhaps you can use some reduce
operation that returns one of the three possible outputs and only processes as many elements as necessary.