gpt4 book ai didi

java - 在 Java 8 中,为什么没有给数组提供 Iterable 的 forEach 方法?

转载 作者:IT老高 更新时间:2023-10-28 20:40:19 28 4
gpt4 key购买 nike

我一定是错过了什么。

在 Java 5 中,"for-each loop" statement (also called the enhanced for loop)被介绍了。似乎它主要是为了迭代Collections而引入的。任何实现 Iterable 的集合(或容器)类接口(interface)可以使用“for-each 循环”进行迭代。也许由于历史原因,Java 数组没有实现 Iterable 接口(interface)。但由于数组无处不在,javac 将接受在数组上使用 for-each 循环(生成相当于传统 for 循环的字节码)。

在 Java 8 中,forEach method被添加到 Iterable 接口(interface)作为 default 方法。这使得将 lambda 表达式传递给集合(在迭代时)成为可能(例如 list.forEach(System.out::println))。但同样,阵列不享受这种待遇。 (我知道有一些解决方法)。

是否有技术原因导致 javac 无法增强以在 forEach 中接受数组,就像它在增强的 for 循环中接受数组一样?似乎不需要数组实现 Iterable 就可以生成代码。我是不是太天真了?

这对于语言的新手来说尤其重要,因为它们的语法很简单,所以很自然地使用数组。切换到列表并使用 Arrays.asList(1, 2, 3) 并不自然。

最佳答案

在 Java 语言和 JVM 中,数组有很多特殊情况。数组有一个 API,但它几乎不可见。就好像数组被声明为:

  • implements Cloneable, Serializable
  • public final int length
  • public T[] clone()在哪里 T是数组的组件类型

但是,这些声明在任何地方的任何源代码中都不可见。见 JLS 4.10.3JLS 10.7解释。 CloneableSerializable通过反射可见,并通过调用返回

Object[].class.getInterfaces()

也许令人惊讶的是,length字段和 clone()方法在反射中不可见。 length字段根本不是字段;使用它会变成一个特殊的 arraylength字节码。调用clone()导致实际的虚方法调用,但如果接收方是数组类型,则由 JVM 专门处理。

值得注意的是,数组类没有实现 Iterable界面。

在 Java SE 5 中添加增强型 for 循环(“for-each”)后,它支持右侧表达式的两种不同情况:Iterable或数组类型 ( JLS 14.14.2 )。原因是Iterable增强的for语句对实例和数组的处理完全不同。 JLS的那部分给出了完整的处理,但更简单地说,情况如下。

对于 Iterable<T> iterable , 代码

for (T t : iterable) {
<loop body>
}

是语法糖

for (Iterator<T> iterator = iterable.iterator(); iterator.hasNext(); ) {
t = iterator.next();
<loop body>
}

对于数组 T[] , 代码

for (T t : array) {
<loop body>
}

是语法糖

int len = array.length;
for (int i = 0; i < len; i++) {
t = array[i];
<loop body>
}

现在,为什么要这样做?数组当然可以实现Iterable ,因为它们已经实现了其他接口(interface)。编译器也可以合成 Iterator由数组支持的实现。 (这是有先例的。编译器已经合成了静态的 values()valueOf() 方法,这些方法会自动添加到每个 enum 类中,如 JLS 8.9.3 中所述。)

但是数组是一个非常低级的结构,通过 int 访问数组值(value)预计是极其便宜的操作。从 0 运行循环索引是非常惯用的。到数组的长度,每次加一。数组上的增强型 for 循环正是这样做的。如果使用 Iterable 实现了数组上的增强 for 循环协议(protocol),我想大多数人会惊讶地发现循环数组涉及初始方法调用和内存分配(创建 Iterator ),然后是每个循环迭代的两个方法调用。

所以当默认方法被添加到 Iterable在 Java 8 中,这根本不影响数组。

正如其他人所指出的,如果您有一个数组 int , long , double ,或引用类型,可以使用 Arrays.stream() 之一将其转换为流来电。这提供了对 map() 的访问权限, filter() , forEach()等。

不过,如果 Java 语言和 JVM 中用于数组的特殊情况被 real 构造替换(同时修复一堆其他与数组相关的问题,例如糟糕的处理 2+ 维数组、2^31 长度限制等)。这是 John Rose 领导的“Arrays 2.0”调查的主题。请参阅 John 在 JVMLS 2012 上的演讲(videoslides)。与此讨论相关的想法包括为数组引入实际接口(interface),以允许库插入元素访问,以支持切片和复制等其他操作。

请注意,所有这些都是调查和 future 的工作。在撰写本文时 (2016-02-23),Java 路线图中没有任何关于这些数组增强功能的内容。

关于java - 在 Java 8 中,为什么没有给数组提供 Iterable 的 forEach 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35518471/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com