在Java 8流

时间:2017-06-26 11:51:27

标签: java java-8 java-stream

我在我的流中使用.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()真的只是调试还是我可以这样使用它?
  • 有没有更好的解决方案?
  • 我应该使用我的第二个解决方案吗?

我正在寻找一个正确的解决方案,而不是一个有效的解决方案,所有这些代码都已经在运行。

2 个答案:

答案 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