Java 9 正式发布于 2017 年 9 月 21 日 。作为 Java8 之后 3 年半才发布的新版本,Java 9 带 来了很多重大的变化。其中最重要的改动是 Java 平台模块系统的引入。除此之外,还有一些新的特性。 本文对 Java9 中包含的新特性做了概括性的介绍,可以帮助你快速了解 Java 9。
一、JShell工具
jshell 是 Java 9 新增的一个实用工具。jshell 为 Java 增加了类似 NodeJS 和 Python 中的读取-求值-打印循环( Read-Evaluation-Print Loop ) 。 在 jshell 中 可以直接 输入表达式并查看其执行结果。当需要测试一个方法的运行效果,或是快速的对表达式进行求值时,jshell 都非常实用。
jshell位于G:\jdk-11.0.5\bin jdk的bin目录。双击进入。
我们可以在命令行界面,输入一些简单的函数。下面举例添加add()方法。回车
然后直接调用add()方法。
jshell方式更适合新手去学习Java的基础。
二、java模块化系统
ava 平台模块系统,也就是 Project Jigsaw,把模块化开发实践引入到了 Java 平台中。在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具,创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。这对于目前流行的不可变基础设施的实践来说,镜像的大小的减少可以节省很多存储空间和带宽资源 。
模块化开发的实践在软件开发领域并不是一个新的概念。Java 开发社区已经使用这样的模块化实践有相当长的一段时间。主流的构建工具,包括 Apache Maven 和 Gradle 都支持把一个大的项目划分成若干个子项目。子项目之间通过不同的依赖关系组织在一起。每个子项目在构建之后都会产生对应的 JAR 文件。 在 Java9 中 ,已有的这些项目可以很容易的升级转换为 Java 9 模块 ,并保持原有的组织结构不变。
Java 9 模块的重要特征是在其工件(artifact)的根目录中包含了一个描述模块的 module-info.class 文 件。 工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。这个文件由根目录中的源代码文件 module-info.java 编译而来。该模块声明文件可以描述模块的不同特征。模块声明文件中可以包含的内容如下:
模块导出的包:使用 exports 可以声明模块对其他模块所导出的包。包中的 public 和 protected 类型,以及这些类型的 public 和 protected 成员可以被其他模块所访问。没有声明为导出的包相当于模块中的私有成员,不能被其他模块使用。
模块的依赖关系:使用 requires 可以声明模块对其他模块的依赖关系。使用 requires transitive 可 以把一个模块依赖声明为传递的。传递的模块依赖可以被依赖当前模块的其他模块所读取。 如果一个模块所导出的类型的型构中包含了来自它所依赖的模块的类型,那么对该模块的依赖应该声明为传递的。
服务的提供和使用:如果一个模块中包含了可以被 ServiceLocator 发现的服务接口的实现 ,需要使用 provides with 语句来声明具体的实现类 ;如果一个模块需要使用服务接口,可以使用 uses 语句来声明。
代码清单 中给出了一个模块声明文件的示例。在该声明文件中,模块 c om.mycompany.sample 导出了 Java 包 com.mycompany.sample。该模块依赖于模块 c om.mycompany.common。该模块也提供了服务接口 com.mycompany.common.DemoService 的实现类 c om.mycompany.sample.DemoServiceImpl 。
module com.mycompany.sample {
exports com.mycompany.sample;
requires com.mycompany.common;
provides com.mycompany.common.DemoService with
com.mycompany.sample.DemoServiceImpl;
}
三、集合、Stream 和 Optional
在集合上,Java 9 增加 了 List.of()、Set.of()、Map.of() 和 M ap.ofEntries()等工厂方法来创建不可变集合 ,传入的参数不可为null,否则会抛出空指针,如果在不可变集合中添加元素,则会抛出 java.lang.UnsupportedOperationException 如 代码清单 所示。
清单 . 创建不可变集合:
List.of();
List.of("Hello", "World");
List.of(1, 2, 3);
Set.of();
Set.of("Hello", "World");
Set.of(1, 2, 3);
Map.of();
Map.of("Hello", 1, "World", 2);
Stream 中增加了新的方法 ofNullable、dropWhile、takeWhile 和 iterate。在 代码清单 中,流中包含了从 1 到 5 的 元素。断言检查元素是否为奇数。第一个元素 1 被删除,结果流中包含 4 个元素。
清单 . Stream 中的 dropWhile 方法示例
@Test
public void testDropWhile() throws Exception {
final long count = Stream.of(1, 2, 3, 4, 5)
.dropWhile(i -> i % 2 != 0)
.count();
assertEquals(4, count);
}
Collectors 中增加了新的方法 filtering 和 flatMapping。在 代码清单 中,对于输入的 String 流 ,先通过 flatMapping 把 String 映射成 Integer 流 ,再把所有的 Integer 收集到一个集合中。
清单 . Collectors 的 flatMapping 方法示例
@Test
public void testFlatMapping() throws Exception {
final Set<Integer> result = Stream.of("a", "ab", "abc")
.collect(Collectors.flatMapping(v -> v.chars().boxed(),
Collectors.toSet()));
assertEquals(3, result.size());
}
Optiona l 类中新增了 ifPresentOrElse、or 和 stream 等方法。在 代码清单 中,Optiona l 流中包含 3 个 元素,其中只有 2 个有值。在使用 flatMap 之后,结果流中包含了 2 个值。
清单 . Optional 的 stream 方法示例
@Test
public void testStream() throws Exception {
final long count = Stream.of(
Optional.of(1),
Optional.empty(),
Optional.of(2)
).flatMap(Optional::stream)
.count();
assertEquals(2, count);
}
四、String底层存储结构更换
java8之前,String的底层都采用了char[]数组的形式进行字符串存储,但是在java9里面,char[] 就替换成 byte[] 这样来讲,更节省了空间和提高了性能。
之所以替换是因为 之前一直是最小单位是一个char,用到两个byte,但是java8是基于latin1的,而这个latin1编码可以用一个byte标识,所以当你数据明明可以用到一个byte的时候,我们用到了一个最小单位chat两个byte,就多出了一个byte的空间。所以java9在这一方面进行了更新,现在的java9 是基于ISO/latin1/Utf-16 ,latin1和ISO用一个byte标识,UTF-16用两个byte标识,java9会自动识别用哪个编码,当数据用到1byte,就会使用iSO或者latin1 ,当空间数据满足2byte的时候,自动使用utf-16,节省了很多空间。随之StringBuffer,StringBuilder也替换了。
五、新增HttpClient
相信大家之前在使用java发送http请求时,大多都是通过maven添加httpclient ,java9直接引入即可,Java9所有特性都是为了提高性能和内存。