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 ByteBuffers 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.