Java – combine allmatch, nonematch, and anymatch on a single stream
I think there is the following logic: (I know it doesn't work because it consumes the stream more than once) But I don't know 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 this?
Solution
Due to super The result of getbuffers() is list < ByteBuffer >, so you can iterate 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 in all cases, this still does not require iterating over all elements Allmatch returns immediately when a non - matching element is encountered, and nonematch returns immediately when a matching element is encountered Therefore, in parallel_ In the case of sent, it may draw conclusions without looking at all the elements
Another option 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 state of the first element determines the conditions we must check As long as there are conflicting elements, allmatch returns immediately, and we have a partition_ Sent situation Otherwise, all elements match the first, indicating "all sent" or "not sent"
Pre checking an empty list produces the same behavior as the original code and ensures that get (0) is never interrupted
If you do have a stream instead of a source that can be iterated many times, there is no simple quick solution because this requires stateful predicates However, there are some simple solutions that deal with 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);