在此版本中引入Java 平台模块系统。
Java 平台模块系统引入了一种新的 Java 编程组件,即模块,它是一个命名的、自描述的代码和数据的集合。它的代码被组织成一组包含类型的包,即Java类和接口;它的数据包括资源和其他种类的静态信息。模块可以导出或封装包,它们显式地表达对其他模块的依赖。
JDK的模块化如下图:
也可以参考链接:openjdk9模块
为了提供可靠的配置和强大的封装,开发人员可以使用并且现有工具链可以支持,我们将模块视为一种基本的新型 Java 程序组件。模块是一个命名的、自描述的代码和数据集合。它的代码被组织成一组包含类型的包, 即Java 类和接口;它的数据包括资源和其他种类的静态信息。
模块的自我描述在其模块声明中表达,这是 Java 编程语言的一种新结构。最简单的模块声明仅指定其模块的名称:
module com.foo.bar { }
可以添加一个或多个requires子句来声明该模块在编译时和运行时按名称依赖于其他一些模块
module com.foo.bar {
requires org.baz.qux;
}
最后,exports可以添加子句来声明模块使特定包中的所有公共类型可供其他模块使用:
module com.foo.bar {
requires org.baz.qux;
exports com.foo.bar.alpha;
exports com.foo.bar.beta;
}
如果模块的声明不包含exports子句,那么它根本不会将任何类型导出到任何其他模块。
按照惯例,模块声明的源代码放置在一个名为module-info.java模块源文件层次结构根目录的文件中。com.foo.bar模块的源文件,例如,可能包括:
module-info.java
com/foo/bar/alpha/AlphaFactory.java
com/foo/bar/alpha/Alpha.java
按照惯例,模块声明被编译成一个名为 的文件 module-info.class,类似地放置在类文件输出目录中。
模块名称,如包名称,不得冲突。命名模块的推荐方法是使用长期以来被推荐用于命名包的反向域名模式。因此,模块的名称通常是其导出包名称的前缀,但这种关系不是强制性的。
如果您已经将资源作为变量final或有效final变量,则可以在try-with-resources语句中使用该变量而无需声明新变量。“有效最终”变量是其值在初始化后从未更改过的变量 。
例如,您声明了这两个资源:
// A final resource
final Resource resource1 = new Resource("resource1");
// An effectively final resource
Resource resource2 = new Resource("resource2");
//在 Java SE 7 或 8 中,将声明新变量r1和r2,如下所示:
try (Resource r1 = resource1;
Resource r2 = resource2) {
//...
}
// Java SE 9 中,不需要声明r1and r2:
try (Resource r1 = resource1;
Resource r2 = resource2) {
//...
}
如果您使用下划线字符(“_”)作为标识符,您的源代码将无法再编译。
支持私有接口方法。这种支持允许接口的非抽象方法在它们之间共享代码。
在此版本中引入。Local-Variable Type Inference 将类型推断扩展到使用初始化程序的局部变量声明
以下示例中显示的代码似乎是多余的,并且使代码更难阅读。
URL url = new URL("http://www.elastic.link");
URLConnection conn = url.openConnection();
Reader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
一个名为的新标识符var现在可用于具有非空初始值设定项的局部变量。使用这个标识符,变量的类型是从上下文中推断出来的。上一个示例中的代码可以重写,如下例所示:
var url = new URL("http://www.elastic.link");
var conn = url.openConnection();
var reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
var是保留的类型名称,而不是关键字,这意味着var用作变量、方法或包名称的现有代码不受影响。但是,var用作类或接口名称的代码会受到影响,需要重命名类或接口。
var可用于以下类型的变量:
以下代码显示了使用示例var:
var list = new ArrayList<String>(); // 推断 ArrayList<String>
var stream = list.stream(); // 推断 Stream<String>
var path = Paths.get(fileName); // 推断路径
var bytes = Files.readAllBytes(path); // 推断 bytes[]
for (var counter=0; counter<10; counter++) {...} // 推断 int
try (var input =
new FileInputStream ("validation.txt")) {...} //文件输入流
相关英文文档可以参考局部类型推断
var在 JDK 11 及更高版本中,您可以使用标识符 声明隐式类型 lambda 表达式的每个形式参数:
隐式类型 lambda 表达式的形式参数声明:其形式参数具有推断类型的 lambda 表达式是隐式类型的:
BiFunction<Integer, Integer, Integer> = (a, b) -> a + b;
var在 JDK 11 及更高版本中,您可以使用标识符 声明隐式类型 lambda 表达式的每个形式参数:
(var a, var b) -> a + b;
因此,隐式类型 lambda 表达式中形式参数声明的语法与局部变量声明的语法一致;将var标识符应用于隐式类型 lambda 表达式中的每个形式参数与根本不使用具有相同的效果var。
您不能var在隐式类型的 lambda 表达式中混合推断形式参数和 - 声明的形式参数,也不能var在显式类型的 lambda 表达式中混合 - 声明的形式参数和清单类型。不允许使用以下示例:
(var x, y) -> x.process(y) // Cannot mix var and inferred formal parameters
// in implicitly typed lambda expressions
(var x, int y) -> x.process(y) // Cannot mix var and manifest types
// in explicitly typed lambda expressions
查看原文,技术咨询与支持,可以扫描微信公众号进行回复咨询