- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我一定是错过了什么。
在 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.3和 JLS 10.7解释。 Cloneable
和 Serializable
通过反射可见,并通过调用返回
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 上的演讲(video、slides)。与此讨论相关的想法包括为数组引入实际接口(interface),以允许库插入元素访问,以支持切片和复制等其他操作。
请注意,所有这些都是调查和 future 的工作。在撰写本文时 (2016-02-23),Java 路线图中没有任何关于这些数组增强功能的内容。
关于java - 在 Java 8 中,为什么没有给数组提供 Iterable 的 forEach 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35518471/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!