流中的非终端forEach()?

Ian*_*Ian 18 java java-stream

有时在处理Java流()时,我发现自己需要使用非终端forEach()来触发副作用,但不会终止处理.

我怀疑我可以使用类似.map(item - > f(item))的方法执行此操作,其中方法f执行副作用并将项目返回到流,但它似乎有点笨拙.

有没有一种标准的处理方式?

Tho*_*ger 14

就在这里.它被称为peek()(来自JavaDoc的示例):

Stream.of("one", "two", "three", "four")
     .peek(e -> System.out.println("Original value: " + e))
     .filter(e -> e.length() > 3)
     .peek(e -> System.out.println("Filtered value: " + e))
     .map(String::toUpperCase)
     .peek(e -> System.out.println("Mapped value: " + e))
     .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 虽然没有终端方法,单独偷看不会做任何事情. (6认同)
  • [这个答案](http://stackoverflow.com/a/33636377/2711488)提供了当用于非调试目的时,`peek`如何破坏或不按预期工作的示例. (5认同)
  • 如果你的元素需要不止一个`Consumer`,你也可以用`c1.andThen(c2)`链接你的`Consumer`s(假设`c1`和`c2`是'Consumer`s) (4认同)
  • @Thomas:谢谢.偷看,这是一个显而易见的名字.我到底怎么想念那个......!:) (3认同)
  • @Ian是的,但你的问题特别要求"非终端forEach".我只是想强调,这不是像每个人一样.实际上,使用peek修改项目是正式不受欢迎的.用于非变异操作是"可以的",但它适用于日志记录等交叉问题. (2认同)

Mat*_*ead 10

不,那里没有。

peek()仅在被以下操作强制时对所有元素进行操作。你能预测这段代码会打印什么吗?

public class Test
{
    private static final AtomicBoolean FLAG = new AtomicBoolean(false);

    private static void setFlagIfGreaterThanZero(int val)
    {
        if (val > 0) {
            FLAG.set(true);
        }
    }

    public static void main(String[] args)
    {
        FLAG.set(false);

        // Test 1
        IntStream.range(0, 10)
                 .peek(Test::setFlagIfGreaterThanZero)
                 .findFirst();

        System.out.println(FLAG.get());
        FLAG.set(false);

        // Test 2
        IntStream.range(0, 10)
                 .peek(Test::setFlagIfGreaterThanZero)
                 .sorted()
                 .findFirst();

        System.out.println(FLAG.get());
        FLAG.set(false);

        // Test 3
        IntStream.range(0, 10)
                 .boxed()
                 .peek(Test::setFlagIfGreaterThanZero)
                 .sorted()
                 .findFirst();

        System.out.println(FLAG.get());
        FLAG.set(false);

        // Test 4
        IntStream.range(0, 10)
                 .peek(Test::setFlagIfGreaterThanZero)
                 .filter(x -> x == 0)
                 .toArray();

        System.out.println(FLAG.get());
    }
}
Run Code Online (Sandbox Code Playgroud)

答案是:




如果你有Java流有扎实的理解这输出可能是直观的,但希望它也预示着这是一个非常糟糕的主意依靠peek()作为中游forEach()

map()也遇到同样的问题。据我所知,没有 Stream 操作可以保证在每种情况下都独立于先前和后续操作的“处理每个元素而不走捷径”行为。

尽管这可能很痛苦,但 Streams 的短路行为是一个重要特性。您可能会发现这个出色的答案很有用:https : //stackoverflow.com/a/32194320/507761