在单个流上组合allMatch,noneMatch和anyMatch

我想有以下逻辑:(我知道它不起作用,因为它不止一次地消耗流)。 但我不知道如何实现它。

Stream 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; } 

我怎样才能做到这一点?

由于super.getBuffers()的结果是List ,因此可以迭代两次。

 List 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; } 

请注意,在所有情况下,这仍然不需要遍历所有元素。 allMatch在遇到非匹配元素时noneMatch返回, noneMatch在遇到匹配元素时noneMatch返回。 因此,在PARTIALLY_SENT情况下,它可能在不查看所有元素的情况下得出结论。

另一种选择是

 List buffers = super.getBuffers(); if(buffers.isEmpty()) return OutgoingMessageStatus.FULLY_SENT; Predicate 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; } 

第一个元素的状态决定了我们必须检查的条件。 只要存在矛盾元素, allMatch立即返回,并且我们有一个allMatch情况。 否则,所有元素都匹配第一个,表示“全部已发送”或“未发送”。

对空列表进行预检查会产生与原始代码相同的行为,并确保get(0)永不中断。


如果你真的有一个Stream而不是你可以多次迭代的源,那么就没有简单的快捷解决方案,因为这需要一个有状态的谓词。 但是,有一些处理所有元素的简单解决方案。

 Map 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; 

要么

 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); 

您可以使用filter() ,然后计算传递它的元素数:

 Stream 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; } 

这假设Stream的数据源( super.getBuffers() )具有size()方法。 如果没有,你可以使用一个额外的变量计算ByteBuffer的总数(不太优雅,我知道):

 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; } 

这种方法的缺点是,当只有一些元素通过filter时(即输出应为OutgoingMessageStatus.PARTIALLY_SENT ),它不会快速失败。 也许您可以使用一些reduce操作来返回三个可能的输出之一,并且只根据需要处理尽可能多的元素。

您需要一个集合来重用它。

您可以使用count()而不是collect(toList())具体取决于您是否需要结果。

 List list = super.getBuffers(); List buffers = list.stream().filter(b -> b.position() > 0).collect(toList()); if (buffers.size() == list.size()) { return OutgoingMessageStatus.FULLY_SENT; } else if (buffers.isEmpty()) { return OutgoingMessageStatus.WAS_NOT_SENT; } else { return OutgoingMessageStatus.PARTIALLY_SENT; }