如何在Java 8中创建漂亮的迭代

受Adam Bien的博客启发,我想用Java 8将Java 7中的常见迭代替换为更好的迭代。旧代码看起来像这样:

void repeatUsingJava7(int times) { for (int i = 0; i < times; i++) { doStuff(); doMoreStuff(); doEvenMoreStuff(); } } 

……这不太好。 所以我用Adam Bein的例子替换了它:

 void repeatUsingJava8(int times) { IntStream.range(0, times).forEach( i -> { doStuff(); doMoreStuff(); doEvenMoreStuff(); } ); } 

…这是向正确方向迈出的一步,但不会使代码更易于阅读,还会引入一个不需要的变量i ,以及一对额外的花括号。 所以现在我想知道是否有其他方法来编写这个代码,这将使它更好,更容易阅读,主要是使用Java 8。

为了完整起见,这是一个不需要计数器变量的解决方案:

 void repeatUsingJava8(int times) { Collections.nCopies(times, ()->{ doStuff(); doMoreStuff(); doEvenMoreStuff(); }).forEach(Runnable::run); } 

如果只有一个方法被times调用,它将变得更具可读性,因为在这种情况下它可以被写为例如

 void repeatUsingJava8(int times) { Collections.nCopies(times, this::doStuff).forEach(Runnable::run); } 

如果它必须是Stream s,则上面的代码相当于

 void repeatUsingJava8(int times) { Stream.generate(()->this::doStuff).limit(times).forEach(Runnable::run); } 

然而,这些替代品并不比优秀的旧循环更好。 如果你考虑parallel执行,这是Stream对普通for循环的真正优势,那么仍然存在基于众所周知的已批准API的替代方案:

 ExecutorService es=Executors.newCachedThreadPool(); es.invokeAll(Collections.nCopies(times, Executors.callable(()->{ doStuff(); doMoreStuff(); doEvenMoreStuff(); }))); 

在这种情况下,我认为使用Streams没有任何优势。 流对于处理包含多个相同类型元素的集合,数组和其他数据结构非常有用。

在这里,您不处理任何数据,只需多次重复相同的操作即可。 没有理由为此目的替换旧的for循环。

正如其他人已经指出的那样,对于这个具体示例,用流替换简单的for循环不一定更好。 但是,如果您尝试解决的问题更为普遍,则会出现优势。 例如,假设您需要重复一些作为参数传递的代码,而不是重复某些特定代码n次? 考虑:

 void repeat(int count, Runnable action) { IntStream.range(0, count).forEach(i -> action.run()); } 

现在你可以写,

 repeat(3, () -> System.out.println("Hello!")); 

也许

 repeat(4, this::doStuff); 

也许n次执行单个动作,你想要执行n多个动作。 你可以这样做:

 void repeat(int count, Runnable... actions) { IntStream.range(0, count).forEach(i -> Arrays.asList(actions).forEach(Runnable::run)); } 

然后你就可以写:

 repeat(5, this::doStuff, this::doMoreStuff, this::doEvenMoreStuff); 

repeat实现比传统的Java 7方式更简洁(可能更简洁):

 void repeatOldWay(int count, Runnable...actions) { for (int i = 0; i < count; i++) { for (Runnable r : actions) { r.run(); } } } 

真正的优势在于调用站点,您可以在其中简单地传入计数和一个或多个lambda表达式或方法引用,而不是复制嵌套的for循环逻辑。

您还可以使用谓词:

 IntStream.range(0, 10).sorted().filter(i -> i > 5).forEach(System.out::println); 

已排序和文件管理器是额外的。