我在我的流中使用.peek(),但它很不满意,遗憾的是我无法找到解决方案。
简化版:
static boolean fooAddTester(int size) {
Foo foo = new foo(); //data structure
return IntStream.range(0, size).
.peek(i -> synchronized(r){foo.add(i)})
.allMatch(e -> foo.isLegal());
}
我需要做的是迭代IntStream并在每次插入后检查,如果foo数据结构合法的话。 这在逻辑上等同于:
static boolean fooAddTester(int size) {
Foo foo = new foo(); //data structure
for(int i=0; i<size; i++){
foo.add(i);
if(!foo.isLegal())
return false;
return true;
}
然而,它更复杂,我正在尝试使用流来简化和学习。
在不使用.peek()
的情况下执行相同操作的方法是:它确实有效 - 但我只是将问题“移动”到.allMatch()
:
return IntStream.range(0, size).
.allMatch(i -> {
synchronized(r){foo.add(i)};
foo.isLegal();
)};
我的问题与this question非常相似,不同之处在于我每次都在检查,因此解决方案无效。
所以我的问题是:
.peek()
真的只是调试还是我可以这样使用它?我正在寻找一个正确的解决方案,而不是一个有效的解决方案,所有这些代码都已经在运行。
答案 0 :(得分:5)
Stream#peek
的文档提到如下,主要不是绝对:
此方法存在主要以支持调试,您希望在元素流经管道中的某个点时查看元素
@Holger绝对回答了这个问题:
使用peek
可以执行最有用的事情是找出是否已处理流元素。
以及他在答案中指出的一些副作用,peek
操作取决于调用哪个终端操作。因此,在内部使用peek
时,您应该小心。
所以正确的方法是使用for-each
循环,因为Stream#collect
不支持short-circuiting operation。
可选方法是使用peek
,因为您可以自己控制流。你需要删除synchornized
块,这里没有必要。
return IntStream.range(0, size).peek(foo::add).allMatch(__ -> Foo.isLegal(foo));
答案 1 :(得分:2)
如果您真的想在逻辑之前使用其他流操作,我只能想到一种方法,但我并不是它的忠实粉丝...
boolean result = true;
try {
IntStream.range(0, 10)
.forEachOrdered(x -> {
foo.add(x);
if (!Foo.isLegal(foo)) {
throw new RuntimeException("just because");
}
});
} catch (RuntimeException re) {
result = false;
}
System.out.println(result);
显然,你需要用某种异常替换RuntimeException
。