我想有以下逻辑:(我知道它不起作用,因为它不止一次地消耗了流)。但我不确定如何实现它。
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;
}
我该怎么做?
答案 0 :(得分:8)
由于super.getBuffers()
的结果为List<ByteBuffer>
,您可以迭代两次。
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;
}
请注意,在所有情况下,仍然不需要迭代所有元素。 allMatch
遇到不匹配的元素时会立即返回,noneMatch
会在遇到匹配元素时立即返回。因此,在PARTIALLY_SENT
案例中,它可能在不查看所有元素的情况下得出结论。
另一种选择是
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;
}
第一个元素的状态决定了我们必须检查的条件。只要存在矛盾元素,allMatch
立即返回,我们就会出现PARTIALLY_SENT
情况。否则,所有元素都与第一个元素匹配,这意味着“全部已发送”或“未发送”。
对空列表进行预检查会产生与原始代码相同的行为,并确保get(0)
永不中断。
如果您确实拥有Stream而不是可以多次迭代的源,那么就没有简单的快捷解决方案,因为这需要有状态谓词。但是,有一些处理所有元素的简单解决方案。
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;
或
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);
答案 1 :(得分:4)
您可以使用~/.ssh/alice.pub
,然后计算传递它的元素数量:
filter()
这假设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;
}
(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;
}
),它不会快速失败。也许您可以使用一些OutgoingMessageStatus.PARTIALLY_SENT
操作返回三个可能输出中的一个,并且只根据需要处理多个元素。
答案 2 :(得分:1)
您需要一个集合才能重复使用它。
您可以使用count()
代替collect(toList())
,具体取决于您是否需要结果。
List<ByteBuffer> list = super.getBuffers();
List<ByteBuffer> 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;
}
答案 3 :(得分:1)
我只是想用不同的类型和谓词来解决您遇到的相同问题。找不到满意的答案,所以我这样实现了自己:
Enum
不仅要容纳true
和false
来满足谓词,还要容纳NONE
(用于空集合)和ENTANGLED
(表示集合中的某些元素满足谓词,而某些不满足):
public enum QuantumBoolean {
NONE, TRUE, FALSE, ENTANGLED;
public static QuantumBoolean fromBoolean(boolean bool) {
if (bool) return QuantumBoolean.TRUE;
return QuantumBoolean.FALSE;
}
}
仅当我需要使用特定参数调用.reduce()
时,才能利用Java Stream API并遍历集合,所以我将它们打包到新类中:
public class QuantumBooleanReducer<T> {
private final Predicate<T> predicate;
public static final QuantumBoolean IDENTITY = QuantumBoolean.NONE;
public QuantumBooleanReducer(Predicate<T> predicate) {
this.predicate = predicate;
}
public final QuantumBoolean accumulator(QuantumBoolean state, T element) {
QuantumBoolean newState = QuantumBoolean.fromBoolean(predicate.test(element));
if (QuantumBoolean.NONE.equals(state))
return newState;
if (newState.equals(state))
return state;
return QuantumBoolean.ENTANGLED;
}
public static QuantumBoolean combiner(QuantumBoolean state1, QuantumBoolean state2) {
if (state1.equals(state2))
return state1;
if (QuantumBoolean.NONE.equals(state1))
return state2;
if (QuantumBoolean.NONE.equals(state2))
return state1;
return QuantumBoolean.ENTANGLED;
}
}
然后您可以通过调用类似的方法来解决您的问题:
switch(buffers.stream()
.reduce(QuantumBooleanReducer.IDENTITY,
new QuantumBooleanReducer<ByteBuffer>(buffer -> buffer.position() > 0)::accumulator,
QuantumBooleanReducer::combiner)) {
case FALSE:
return OutgoingMessageStatus.WAS_NOT_SENT;
case TRUE:
return OutgoingMessageStatus.FULLY_SENT;
case ENTANGLED:
return OutgoingMessageStatus.PARTIALLY_SENT;
default:
throw new IllegalStateException("Unexpected Quantum Boolean");
}