在java 8流中使用.peek()

Ada*_*-Ur 11 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());
}
Run Code Online (Sandbox Code Playgroud)

我需要做的是迭代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;
}
Run Code Online (Sandbox Code Playgroud)

然而,它更复杂,我正在尝试使用流来简化和学习.

不使用的方法.peek()是这样做:哪个确实有效 - 但我只是将问题"移动"到.allMatch():

return IntStream.range(0, size).
            .allMatch(i -> {
                 synchronized(r){foo.add(i)};
                 foo.isLegal();
             )};
Run Code Online (Sandbox Code Playgroud)

我的问题与这个问题非常相似,不同之处在于我每次都在检查,因此解决方案无效.

所以我的问题是:

  • 是否.peek()真的仅仅与调试或者我可以以这种方式使用它?
  • 有没有更好的解决方案?
  • 我应该使用第二种解决方案吗?

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

hol*_*ava 5

Stream#peek以下提到的文件,主要不是绝对的:

此方法主要用于支持调试,您希望在元素流经管道中的某个点时查看这些元素

@Holger绝对回答了这个问题:

您可以做的有用的事情peek找出是否已处理流元素.

以及他在答案中指出的一些副作用,peek操作取决于调用哪个终端操作.所以在peek内部使用时你应该小心.

所以正确的方法就是使用for-each循环,因为Stream#collect不支持短路操作.

可选的方法是使用,peek因为您可以自己控制流.你需要删除synchornized块,这里没有必要.

return IntStream.range(0, size).peek(foo::add).allMatch(__ -> Foo.isLegal(foo));
Run Code Online (Sandbox Code Playgroud)

  • 好的是`你可以用peek做的最有用的事情是找出一个流元素是否已被处理.但是通过记录,而不是依赖于副作用.一旦你添加"并行",这将以神秘的方式打破.synchronized将确保一次只处理一个元素,但即使这样你也不知道哪个元素有*处理顺序*. (4认同)