Java Streams with state - 一项简单的练习

Sym*_*Sym 3 java fold java-8 java-stream

在获得Java 8流程的过程中,以下练习阻止了我.

鉴于IntStream.range(0, 6).生成以下字符串流:

"0, 1"
"1, 2"
"2, 3"
"3, 4"
"4, 5"
Run Code Online (Sandbox Code Playgroud)

我想使用Collectors.collectAndThen将它传递给好的旧列表或数组并循环以构造字符串列表,如下所示:

List<String> strgs = new ArrayList<>();
String prev = String.valueOf(nums[0]);
for (int i = 1; i < nums.length; i++) {
    strgs.add(prev+", "+String.valueOf(nums[i]));
    prev = String.valueOf(nums[i]);  
}
Run Code Online (Sandbox Code Playgroud)

但它没有使用流的力量.我觉得Venkat Subramaniam说"我之后想洗个澡".我想知道如何应用功能技术,所以我可以在编码后跳过洗澡!

另外,我想避免像StreamEx或JavaRx这样的库,我想坚持使用普通的Java 8 API.

编辑:@Tunaki,谢谢你在我的问题中指出不清楚的措辞.它是由Stream的两个连续元素组成的对.更具体的,像小溪[1, 3, 5, 7, 9, ...]

"1, 3"
"3, 5"
"5, 7"
...
Run Code Online (Sandbox Code Playgroud)

编辑2

在向所有答案致敬之后,虽然我的问题与Tunaki指出的另一个问题重复.我想扩展一个社区讨论,以寻找Bohemian提供的答案.虽然他的回答不被一些人所厌恶,但它提出了一个严重的问题,即减少手术的副作用.我向社区提出的要求是为该问题提供合理的反有效技术.因此我想重用波希米亚的答案如下:

给定输入:nums = new int [] {1,3,5,7,9}

请考虑以下代码段:

List<CharSequence> stringList = new ArrayList<>();
IntBinaryOperator reductionWithSideEffect = (int left, int right) -> {
        stringList.add(new StringBuilder().append(left).append(", ").append(right));
        return right;
};
Arrays.stream(nums)
        .reduce(reductionWithSideEffect);
System.out.println(String.join(", ", stringList));
Run Code Online (Sandbox Code Playgroud)

Tag*_*eev 7

在我看来,解决这个问题最干净的方法是编写一个自定义分裂器并在其上创建一个Stream.如果你不需要绝对最大的性能并且不关心并行处理(并行流将工作,但效率低下),这并不是很难.像这样的东西会起作用:

public static <T, R> Stream<R> pairMap(BaseStream<T, ?> source,
        BiFunction<? super T, ? super T, ? extends R> mapper) {
    Spliterator<T> spltr = source.spliterator();
    long sourceSize = spltr.estimateSize();
    Spliterator<R> result = new Spliterators.AbstractSpliterator<R>(
            sourceSize > 0 && sourceSize < Long.MAX_VALUE ? sourceSize - 1 : sourceSize,
            spltr.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
        T prev;
        boolean started;

        @Override
        public boolean tryAdvance(Consumer<? super R> action) {
            if (!started) {
                if (!spltr.tryAdvance(t -> prev = t))
                    return false;
                started = true;
            }
            return spltr.tryAdvance(t -> action.accept(mapper.apply(prev, prev = t)));
        }
    };
    return StreamSupport.stream(result, source.isParallel()).onClose(source::close);
}
Run Code Online (Sandbox Code Playgroud)

这里mapper是基于输入流的一对相邻元素创建新流的元素的函数.

用法示例:

pairMap(IntStream.range(0, 6), (a, b) -> a + ", " + b).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

输出:

0, 1
1, 2
2, 3
3, 4
4, 5
Run Code Online (Sandbox Code Playgroud)