在单个流上组合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; }