将for循环转换为java 8流

use*_*416 5 java functional-programming java-8 java-stream

我正在玩Java 8.我在将这个for循环转换为Java 8 Stream时遇到了一些麻烦.

for (int y = 0; y < 5; y ++) {
    for (int x = y; x < 10; x += 2) {
        System.out.println(x+y);
    }
}
Run Code Online (Sandbox Code Playgroud)

请帮忙!

Hol*_*ger 12

转换嵌套循环的规范方法是flatMap在流上使用,例如

IntStream.range(0, 5).flatMap(i->IntStream.range(i, 10))
  .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

你的任务的棘手部分是增加2,因为它在流API中没有直接的等价物.有两种可能性:

  1. 使用IntStream.iterate(y, x->x+2)定义起始值和增量.然后你必须通过limit元素的数量修改无限流:.limit((11-y)/2).

    因此,循环的结果代码如下所示:

    IntStream.range(0, 5)
        .flatMap(y->IntStream.iterate(y, x->x+2).limit((11-y)/2)
        .map(x -> x+y)).forEach(System.out::println);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用IntStream.range(0, (11-y)/2)创造上升的期望数量的流intS和与修改它.map(t->y+t*2)有它产生你的内心的期望值for循环.

    然后,循环的结果代码如下所示:

    IntStream.range(0, 5)
        .flatMap(y->IntStream.range(0, (11-y)/2).map(t->y+t*2).map(x -> x+y))
        .forEach(System.out::println);
    
    Run Code Online (Sandbox Code Playgroud)


ski*_*iwi 7

正如霍尔格已经指出的那样,它肯定是可行的.但问题是:为什么?
我怀疑XY问题,流不是解决所有问题的方法,这是一个需要记住的重要事实.

看看你的代码在做什么,并创建一个方法,做你想做的事情,尽可能多的可变性,你是:

  • 有一个y最大值(考虑到你总是从0开始)
  • 有一个x最大值(考虑到你总是从0开始)
  • y增量操作.(假设+1不固定)
  • x增量操作.
  • 然后用x和的操作y.
  • 然后您使用操作的结果.

因此,我提出以下建议,如果这不是你想要的,可以减少可变性,换句话说:如果需要,你可以更加努力.

private void doMyDoubleLoop(
        final int yEnd, final IntUnaryOperator yIncrementOperator, 
        final int xEnd, final IntUnaryOperator xIncrementOperator,
        final IntBinaryOperator combiner, final IntConsumer consumer
) {
    for (int y = 0; y < yEnd; y = yIncrementOperator.applyAsInt(y)) {
        for (int x = y; x < xEnd; x = xIncrementOperator.applyAsInt(x)) {
            consumer.accept(combiner.applyAsInt(x, y));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用作:

doMyDoubleLoop(5, y -> y + 1, 10, x -> x + 2, (x, y) -> x + y, System.out::println);
Run Code Online (Sandbox Code Playgroud)

正如我所说,这可能是矫枉过正,所以假设围绕for循环的所有内容都是固定的,它突然变得更好了:

private void doMyInternalDoubleLoop(final IntBinaryOperator combiner, final IntConsumer consumer) {
    for (int y = 0; y < 5; y++) {
        for (int x = y; x < 10; x += 2) {
            consumer.accept(combiner.applyAsInt(x, y));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用作:

doMyInternalDoubleLoop((x, y) -> x + y, System.out::println);
Run Code Online (Sandbox Code Playgroud)

这是一个我建议使用的模式,如果你有一个类,你有很多操作使用这个双循环,但不想复制循环,因为它应该与DRY(不要重复)你自己)原则.

  • @JoD.只要"如果它们是循环的流"将会如此难以编码,那么从维护的角度来看,更好地避免它们并使用常规循环,正如我所指出的那样.不要让事情比他们需要的更复杂. (2认同)

小智 1

我仍在尝试自己解决这个问题。以下内容不得分:

IntStream.range(0, 5).forEach(y -> 
//<kludge> 
//I would appreciate it if someone would replace this with something smarter.
    IntStream.iterate(y, x -> x + 2)
        .limit(100)
        .filter(x -> x < 10)
//</kludge>
        .forEach( x -> System.out.println(y+x)));
Run Code Online (Sandbox Code Playgroud)

x += 2是棘手的部分,如果 range 方法有一个“增量”参数,这将是微不足道的。我曾经iterate自己做增量,但iterate产生了无限的流。我曾经filter将其限制在我想要的范围内,并输入任意值,limit这样它就不会溢出并开始吐出小于 10 的大负数。