Java 8 Stream每个索引运行1个函数,而每n次运行另一个函数

apr*_*dia 1 functional-programming java-8 java-stream

什么是迭代Java 8 Stream的最佳方式,这样我可以为每个元素(forEach)执行一个函数,而为每10个元素执行另一个函数.使用foreach的每个元素都显示在下面.我可以使用什么功能来拦截eveyr nth元素并执行第二个函数调用?

示例代码如下: -

Stream<String> strings = Files.lines(path); //some stream

stream.forEach(s -> System::println)// every element but how can i perform 
Run Code Online (Sandbox Code Playgroud)

Fed*_*ner 5

Guava 22版以来,您可以Streams.forEachPair用来完成您想要的任务:

Stream<String> strings = Stream.of("a", "b", "c", "d", "e", "f");

Stream<Long> indexes = Stream.iterate(0L, i -> i + 1L);

Streams.forEachPair(strings, indexes, (s, i) -> {
    if (i % 3 == 0) {
        System.out.println("Every 3rd element: " + s);
    } else {
        System.out.println(s);
    }
});
Run Code Online (Sandbox Code Playgroud)

这将创建一个无限的连续Long元素流,从流开始0L,并在内部使用strings流拉链此流.Streams.forEachPair接受一个BiConsumer接收每对元素的元素,每个元素对应一个元素,并根据索引是否为第3个元素执行操作.

您可以使用以下帮助器方法对此进行更多抽象:

static <T> void forEachNthOrElse(
    Stream<T> stream, 
    int n, 
    Consumer<T> onNthElement,
    Consumer<T> onAnyOther) {

    Streams.forEachPair(
        stream, 
        Stream.iterate(0L, i -> i + 1),
        (t, i) -> {
            Consumer<T> action = i % n == 0 ? onNthElement : onAnyOther;
            action.accept(t);
        });
}
Run Code Online (Sandbox Code Playgroud)

并且,对于相同的示例,您可以按如下方式使用它:

forEachNthOrElse(
    strings, 
    3, 
    s -> System.out.println("Every 3rd element: " + s), 
    System.out::println);
Run Code Online (Sandbox Code Playgroud)

注意:我不确定是否需要System.out::println始终执行操作,或仅在元素不是第n个元素时执行操作.我实现了BiConsumer执行一个动作或另一个动作.如果不是这种情况(即如果你想为第n个元素执行一个动作并且总是执行另一个动作,即使对于第n个元素),你应该相应地改变代码.