我的问题涉及Java 5中引入的Java foreach循环和Java 8中引入的Iterable.forEach()
。
假设存在一个带有List of String值的程序,该程序的功能是迭代每个单独的字符串并将其用作方法参数。
这样的程序在Java 5中看起来像这样:
for (String s : stringList) {
doSomething(s);
}
然而,随着Java 8中Iterable.forEach()
的引入,这样的程序看起来像这样:
stringList.forEach(this::doSomething);
我的问题是,有没有理由使用Iterable.forEach()
代替foreach循环而不是保存几行?
答案 0 :(得分:5)
提供forEach
可以对可插拔的元素执行操作,并且非常灵活。它可以是一个直接的lambda,一个MethodHandle,甚至是一个MethodHanlde,它是由行为的静态部分和运行时定义的部分动态组成的。在内部,可以避免创建显式Iterator
对象。否则,您当然可以通过外部循环模拟相同的行为。这可能看起来不太好。
答案 1 :(得分:5)
以下是两者之间需要考虑的3个差异:
Lambdas无法捕获非最终变量。
forEach
不允许break
/ continue
。
必须在传递的lambda中捕获已检查的异常(因为类型为Consumer<...>
)。
List<MyClass> list = ...;
MyClass mc = null;
for(MyClass e : list) {
if(e.test("bla")) {
mc = e;
break;
}
}
list.forEach(e -> {
if(e.test("bla")) {
mc = e; // Does not compile
break; // Also, does not compile
}
});
void method() throws Exception {
...
for(MyClass e : list) {
...
throw new Exception("Oops");
}
list.forEach(e -> {
...
throw new Exception("Oops"); // Error: unhandled exception
});
}
答案 2 :(得分:3)
基本的好处是内部迭代,如果库决定这样做,你可以使用forEach
。使用增强型for循环(for x : xs
)时,您坚持使用外部迭代。
这个想法是你想要一些函数来获取列表的每个元素(或Iterable
)并用它做一些事情。非功能性(Java中的传统)是迭代代码中的列表并执行它。这称为外部迭代。这迫使顺序执行。
使用Java 8,您可以创建并传递lambda表达式。因此,您传递接受该元素的行为或函数。因此,您放弃对迭代的控制,让列表实现(可以说是库代码)负责迭代,可能并行化工作。
答案 3 :(得分:2)
在新的Java8 API中,您可以执行
之类的操作stringList.stream ().filter(...).map(...).forEach(...)
除了在每个for循环中进行相同的转换和过滤之外,它可以多次清洁且不易出错。