Java for循环
迭代是所有编程语言中最基本的要求之一,而" for"是Java中用于迭代的最广泛使用的循环。
我们将看到Java for循环迭代技术的发展。
Java for循环
我们将通过一个示例来显示一个Collection中的演员姓名。
为了简单起见,让我们列出一个列表并进行设置:
List<String> actors = Arrays.asList("Hyman Nicholson", "Marlon Brando", "Robert De Niro", "Al Pacino", "Tom Hanks");
让我们开始研究不同Java版本上的for循环演变。
基本的循环
" for"循环的主要元素是初始化,终止条件和循环增量逻辑。
让我们在这里看到一个示例:
for (int i = 0; i < actors.size(); i++) { System.out.println(actors.get(i)); }
如果我们要遍历不是List类型的集合,则将没有get(int index)
方法,该方法将为我们提供该集合的索引值。
因此,在Java 1.2中引入了迭代器。
让我们看看我们如何使用迭代器解决相同的问题:
for (Iterator<String> iterator = actors.iterator(); iterator.hasNext();) { System.out.println(iterator.next()); }
for-each(增强了循环)
此循环是Java 5中引入的,它通过完全隐藏迭代器或者索引变量来消除混乱,仪式和出错的机会。
让我们看看实际情况:
for (String actor : actors) { System.out.println(actor); }
以上示例是外部迭代器的类型,此处的控制和终止逻辑驻留在外部迭代器中。
这会导致整体复杂性,并且容易出错。
内部forEach循环
在Java 8中,随着功能接口和Lambda的引入,Java架构师为我们提供了一个由Collection框架支持的内部迭代器(forEach循环),并且可以与collections对象一起使用。
此方法对集合的每个元素执行给定的操作。
让我们更详细地了解一下:
方法签名:public void forEach(Consumer action)
forEach采用了"消费者"(功能接口)的实现,该实现具有一种" accept(T t)"方法来执行循环内的逻辑。
让我们看一下实现:
actors.forEach(new Consumer<String>() { public void accept(String actor) { System.out.println(actor); } });
这里为forEach方法提供了一个消费者内部匿名类接口。
此类具有accept(T t)方法,该方法将为集合的所有值调用。
该代码存在设计缺陷,每次使用forEach时,都会通过传递匿名内部类来创建一个新类。
ForLoopEvolution.class ForLoopEvolution.class
与以前的循环相比,此解决方案看起来更加冗长和复杂。
让我们尝试以简化的方式重构它。
整个功能接口的实现可以编写为更直观的Lambda函数。
让我们看看实际情况:
actors.forEach((e) -> { System.out.println(e); });
对于每个元素e,参与者都显示在控制台中。
可以通过删除不必要的花括号和方括号来进一步简化此代码。
actors.forEach(e -> System.out.println(e));
使用lambda代替匿名内部类的主要优点是,不会污染字节码,也不会创建类,而是将对lambda的调用推迟到运行时。
让我们看一下字节码以获取更多详细信息:
动态调用可以帮助JVM从lambda表达式创建字节码,并将执行延迟到运行时。
方法推论
方法推论进一步消除了更多的仪式和冗长。
让我们重构以传递方法推断而不是lambda:
actors.forEach(System.out::println);
使用内部迭代器的另一个好处是,代码几乎可以并行处理了。
在Java 8中引入了流api之后,我们可以并行运行代码,而无需同步。
可以从集合中创建并行流以处理我们的功能。
actors.parallelStream().forEach(System.out::println);