Latest commit

History

History
260 lines (177 loc) · 12 KB

File metadata and controls

260 lines (177 loc) · 12 KB
titleJava 9 新特性概览
categoryJava
tag
Java新特性

Java 9 发布于 2017 年 9 月 21 日 。作为 Java 8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流......。

你可以在 Archived OpenJDK General-Availability Releases 上下载自己需要的 JDK 版本!官方的新特性说明文档地址: https://openjdk.java.net/projects/jdk/

概览(精选了一部分)

JShell

JShell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。

在 JShell 中可以直接输入表达式并查看其执行结果。

JShell 为我们带来了哪些好处呢?

  1. 降低了输出第一行 Java 版"Hello World!"的门槛,能够提高新手的学习热情。
  2. 在处理简单的小逻辑,验证简单的小问题时,比 IDE 更有效率(并不是为了取代 IDE,对于复杂逻辑的验证,IDE 更合适,两者互补)。
  3. ......

JShell 的代码和普通的可编译代码,有什么不一样?

  1. 一旦语句输入完成,JShell 立即就能返回执行的结果,而不再需要编辑器、编译器、解释器。
  2. JShell 支持变量的重复声明,后面声明的会覆盖前面声明的。
  3. JShell 支持独立的表达式比如普通的加法运算 1 + 1
  4. ......

模块化系统

模块系统是Jigsaw Project的一部分,把模块化开发实践引入到了 Java 平台中,可以让我们的代码可重用性更好!

什么是模块系统? 官方的定义是:

A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor。

简单来说,你可以将一个模块看作是一组唯一命名、可重用的包、资源和模块描述文件(module-info.java)。

任意一个 jar 文件,只要加上一个模块描述文件(module-info.java),就可以升级为一个模块。

在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具 (Jlink 是随 Java 9 一起发布的新命令行工具。它允许开发人员为基于模块的 Java 应用程序创建自己的轻量级、定制的 JRE),创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。

我们可以通过 exports 关键词精准控制哪些类可以对外开放使用,哪些类只能内部使用。

modulemy.module {
//exports 公开指定包的所有公共成员exportscom.my.package.name;
}
modulemy.module {
//exports…to 限制访问的成员范围exportcommy.package.nametocom.specific.package;
}

想要深入了解 Java 9 的模块化,可以参考下面这几篇文章:

G1 成为默认垃圾回收器

在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。

G1 还是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。

快速创建不可变集合

增加了List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合(有点参考 Guava 的味道):

List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);

使用 of() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。

String 存储结构优化

Java 8 及之前的版本,String 一直是用 char[] 存储。在 Java 9 之后,String 的实现改用 byte[] 数组存储字符串,节省了空间。

publicfinalclassStringimplementsjava.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivatefinalbyte[] value;
}

接口私有方法

Java 9 允许在接口中使用私有方法。这样的话,接口的使用就更加灵活了,有点像是一个简化版的抽象类。

publicinterfaceMyInterface {
privatevoidmethodPrivate(){
}
}

try-with-resources 增强

在 Java 9 之前,我们只能在 try-with-resources 块中声明变量:

try (Scannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))) {
// omitted
}

在 Java 9 之后,在 try-with-resources 语句中可以使用 effectively-final 变量。

finalScannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))
try (scanner;writer) {
// omitted
}

什么是 effectively-final 变量? 简单来说就是没有被 final 修饰但是值在初始化后从未更改的变量。

正如上面的代码所演示的那样,即使 writer 变量没有被显示声明为 final,但它在第一次被复制后就不会改变了,因此,它就是 effectively-final 变量。

Stream & Optional 增强

Stream 中增加了新的方法 ofNullable()dropWhile()takeWhile() 以及 iterate() 方法的重载方法。

Java 9 中的 ofNullable() 方 法允许我们创建一个单元素的 Stream,可以包含一个非空元素,也可以创建一个空 Stream。 而在 Java 8 中则不可以创建空的 Stream

Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0

takeWhile() 方法可以从 Stream 中依次获取满足条件的元素,直到不满足条件为止结束获取。

List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33

dropWhile() 方法的效果和 takeWhile() 相反。

List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13

iterate() 方法的新重载方法提供了一个 Predicate 参数 (判断条件)来决定什么时候结束迭代

publicstatic<T> Stream<T> iterate(finalTseed, finalUnaryOperator<T> f) {
}
// 新增加的重载方法publicstatic<T> Stream<T> iterate(Tseed, Predicate<? superT> hasNext, UnaryOperator<T> next) {
}

两者的使用对比如下,新的 iterate() 重载方法更加灵活一些。

// 使用原始 iterate() 方法输出数字 1~10Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 使用新的 iterate() 重载方法输出数字 1~10Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);

Optional 类中新增了 ifPresentOrElse()or()stream() 等方法

ifPresentOrElse() 方法接受两个参数 ConsumerRunnable ,如果 Optional 不为空调用 Consumer 参数,为空则调用 Runnable 参数。

publicvoidifPresentOrElse(Consumer<? superT> action, RunnableemptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!

or() 方法接受一个 Supplier 参数 ,如果 Optional 为空则返回 Supplier 参数指定的 Optional 值。

publicOptional<T> or(Supplier<? extendsOptional<? extendsT>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//java

进程 API

Java 9 增加了 java.lang.ProcessHandle 接口来实现对原生进程进行管理,尤其适合于管理长时间运行的进程。

// 获取当前正在运行的 JVM 的进程ProcessHandlecurrentProcess = ProcessHandle.current();
// 输出进程的 idSystem.out.println(currentProcess.pid());
// 输出进程的信息System.out.println(currentProcess.info());

ProcessHandle 接口概览:

响应式流 ( Reactive Streams )

在 Java 9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口 。

Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

关于 Java 9 响应式流更详细的解读,推荐你看 Java 9 揭秘(17. Reactive Streams )- 林本托 这篇文章。

变量句柄

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。

变量句柄的含义类似于已有的方法句柄 MethodHandle ,由 Java 类 java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对象。

VarHandle 的出现替代了 java.util.concurrent.atomicsun.misc.Unsafe 的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的 API。

其它

  • 平台日志 API 改进 : Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
  • CompletableFuture类增强 :新增了几个新的方法(completeAsyncorTimeout 等)。
  • Nashorn 引擎的增强 :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性(Java 11 中已经被弃用)。
  • I/O 流的新特性 :增加了新的方法来读取和复制 InputStream 中包含的数据。
  • 改进应用的安全性能 :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。
  • 改进方法句柄(Method Handle) :方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄。
  • ......

参考

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

History
260 lines (177 loc) · 12 KB

File metadata and controls

260 lines (177 loc) · 12 KB
titleJava 9 新特性概览
categoryJava
tag
Java新特性

Java 9 发布于 2017 年 9 月 21 日 。作为 Java 8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流......。

你可以在 Archived OpenJDK General-Availability Releases 上下载自己需要的 JDK 版本!官方的新特性说明文档地址: https://openjdk.java.net/projects/jdk/

概览(精选了一部分)

JShell

JShell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。

在 JShell 中可以直接输入表达式并查看其执行结果。

JShell 为我们带来了哪些好处呢?

  1. 降低了输出第一行 Java 版"Hello World!"的门槛,能够提高新手的学习热情。
  2. 在处理简单的小逻辑,验证简单的小问题时,比 IDE 更有效率(并不是为了取代 IDE,对于复杂逻辑的验证,IDE 更合适,两者互补)。
  3. ......

JShell 的代码和普通的可编译代码,有什么不一样?

  1. 一旦语句输入完成,JShell 立即就能返回执行的结果,而不再需要编辑器、编译器、解释器。
  2. JShell 支持变量的重复声明,后面声明的会覆盖前面声明的。
  3. JShell 支持独立的表达式比如普通的加法运算 1 + 1
  4. ......

模块化系统

模块系统是Jigsaw Project的一部分,把模块化开发实践引入到了 Java 平台中,可以让我们的代码可重用性更好!

什么是模块系统? 官方的定义是:

A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor。

简单来说,你可以将一个模块看作是一组唯一命名、可重用的包、资源和模块描述文件(module-info.java)。

任意一个 jar 文件,只要加上一个模块描述文件(module-info.java),就可以升级为一个模块。

在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具 (Jlink 是随 Java 9 一起发布的新命令行工具。它允许开发人员为基于模块的 Java 应用程序创建自己的轻量级、定制的 JRE),创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。

我们可以通过 exports 关键词精准控制哪些类可以对外开放使用,哪些类只能内部使用。

modulemy.module {
//exports 公开指定包的所有公共成员exportscom.my.package.name;
}
modulemy.module {
//exports…to 限制访问的成员范围exportcommy.package.nametocom.specific.package;
}

想要深入了解 Java 9 的模块化,可以参考下面这几篇文章:

G1 成为默认垃圾回收器

在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。

G1 还是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。

快速创建不可变集合

增加了List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合(有点参考 Guava 的味道):

List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);

使用 of() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。

String 存储结构优化

Java 8 及之前的版本,String 一直是用 char[] 存储。在 Java 9 之后,String 的实现改用 byte[] 数组存储字符串,节省了空间。

publicfinalclassStringimplementsjava.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivatefinalbyte[] value;
}

接口私有方法

Java 9 允许在接口中使用私有方法。这样的话,接口的使用就更加灵活了,有点像是一个简化版的抽象类。

publicinterfaceMyInterface {
privatevoidmethodPrivate(){
}
}

try-with-resources 增强

在 Java 9 之前,我们只能在 try-with-resources 块中声明变量:

try (Scannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))) {
// omitted
}

在 Java 9 之后,在 try-with-resources 语句中可以使用 effectively-final 变量。

finalScannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))
try (scanner;writer) {
// omitted
}

什么是 effectively-final 变量? 简单来说就是没有被 final 修饰但是值在初始化后从未更改的变量。

正如上面的代码所演示的那样,即使 writer 变量没有被显示声明为 final,但它在第一次被复制后就不会改变了,因此,它就是 effectively-final 变量。

Stream & Optional 增强

Stream 中增加了新的方法 ofNullable()dropWhile()takeWhile() 以及 iterate() 方法的重载方法。

Java 9 中的 ofNullable() 方 法允许我们创建一个单元素的 Stream,可以包含一个非空元素,也可以创建一个空 Stream。 而在 Java 8 中则不可以创建空的 Stream

Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0

takeWhile() 方法可以从 Stream 中依次获取满足条件的元素,直到不满足条件为止结束获取。

List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33

dropWhile() 方法的效果和 takeWhile() 相反。

List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13

iterate() 方法的新重载方法提供了一个 Predicate 参数 (判断条件)来决定什么时候结束迭代

publicstatic<T> Stream<T> iterate(finalTseed, finalUnaryOperator<T> f) {
}
// 新增加的重载方法publicstatic<T> Stream<T> iterate(Tseed, Predicate<? superT> hasNext, UnaryOperator<T> next) {
}

两者的使用对比如下,新的 iterate() 重载方法更加灵活一些。

// 使用原始 iterate() 方法输出数字 1~10Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 使用新的 iterate() 重载方法输出数字 1~10Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);

Optional 类中新增了 ifPresentOrElse()or()stream() 等方法

ifPresentOrElse() 方法接受两个参数 ConsumerRunnable ,如果 Optional 不为空调用 Consumer 参数,为空则调用 Runnable 参数。

publicvoidifPresentOrElse(Consumer<? superT> action, RunnableemptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!

or() 方法接受一个 Supplier 参数 ,如果 Optional 为空则返回 Supplier 参数指定的 Optional 值。

publicOptional<T> or(Supplier<? extendsOptional<? extendsT>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//java

进程 API

Java 9 增加了 java.lang.ProcessHandle 接口来实现对原生进程进行管理,尤其适合于管理长时间运行的进程。

// 获取当前正在运行的 JVM 的进程ProcessHandlecurrentProcess = ProcessHandle.current();
// 输出进程的 idSystem.out.println(currentProcess.pid());
// 输出进程的信息System.out.println(currentProcess.info());

ProcessHandle 接口概览:

响应式流 ( Reactive Streams )

在 Java 9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口 。

Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

关于 Java 9 响应式流更详细的解读,推荐你看 Java 9 揭秘(17. Reactive Streams )- 林本托 这篇文章。

变量句柄

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。

变量句柄的含义类似于已有的方法句柄 MethodHandle ,由 Java 类 java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对象。

VarHandle 的出现替代了 java.util.concurrent.atomicsun.misc.Unsafe 的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的 API。

其它

  • 平台日志 API 改进 : Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
  • CompletableFuture类增强 :新增了几个新的方法(completeAsyncorTimeout 等)。
  • Nashorn 引擎的增强 :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性(Java 11 中已经被弃用)。
  • I/O 流的新特性 :增加了新的方法来读取和复制 InputStream 中包含的数据。
  • 改进应用的安全性能 :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。
  • 改进方法句柄(Method Handle) :方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄。
  • ......

参考

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

History
260 lines (177 loc) · 12 KB

File metadata and controls

260 lines (177 loc) · 12 KB
titleJava 9 新特性概览
categoryJava
tag
Java新特性

Java 9 发布于 2017 年 9 月 21 日 。作为 Java 8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流......。

你可以在 Archived OpenJDK General-Availability Releases 上下载自己需要的 JDK 版本!官方的新特性说明文档地址: https://openjdk.java.net/projects/jdk/

概览(精选了一部分)

JShell

JShell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。

在 JShell 中可以直接输入表达式并查看其执行结果。

JShell 为我们带来了哪些好处呢?

  1. 降低了输出第一行 Java 版"Hello World!"的门槛,能够提高新手的学习热情。
  2. 在处理简单的小逻辑,验证简单的小问题时,比 IDE 更有效率(并不是为了取代 IDE,对于复杂逻辑的验证,IDE 更合适,两者互补)。
  3. ......

JShell 的代码和普通的可编译代码,有什么不一样?

  1. 一旦语句输入完成,JShell 立即就能返回执行的结果,而不再需要编辑器、编译器、解释器。
  2. JShell 支持变量的重复声明,后面声明的会覆盖前面声明的。
  3. JShell 支持独立的表达式比如普通的加法运算 1 + 1
  4. ......

模块化系统

模块系统是Jigsaw Project的一部分,把模块化开发实践引入到了 Java 平台中,可以让我们的代码可重用性更好!

什么是模块系统? 官方的定义是:

A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor。

简单来说,你可以将一个模块看作是一组唯一命名、可重用的包、资源和模块描述文件(module-info.java)。

任意一个 jar 文件,只要加上一个模块描述文件(module-info.java),就可以升级为一个模块。

在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具 (Jlink 是随 Java 9 一起发布的新命令行工具。它允许开发人员为基于模块的 Java 应用程序创建自己的轻量级、定制的 JRE),创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。

我们可以通过 exports 关键词精准控制哪些类可以对外开放使用,哪些类只能内部使用。

modulemy.module {
//exports 公开指定包的所有公共成员exportscom.my.package.name;
}
modulemy.module {
//exports…to 限制访问的成员范围exportcommy.package.nametocom.specific.package;
}

想要深入了解 Java 9 的模块化,可以参考下面这几篇文章:

G1 成为默认垃圾回收器

在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。

G1 还是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。

快速创建不可变集合

增加了List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合(有点参考 Guava 的味道):

List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);

使用 of() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。

String 存储结构优化

Java 8 及之前的版本,String 一直是用 char[] 存储。在 Java 9 之后,String 的实现改用 byte[] 数组存储字符串,节省了空间。

publicfinalclassStringimplementsjava.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivatefinalbyte[] value;
}

接口私有方法

Java 9 允许在接口中使用私有方法。这样的话,接口的使用就更加灵活了,有点像是一个简化版的抽象类。

publicinterfaceMyInterface {
privatevoidmethodPrivate(){
}
}

try-with-resources 增强

在 Java 9 之前,我们只能在 try-with-resources 块中声明变量:

try (Scannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))) {
// omitted
}

在 Java 9 之后,在 try-with-resources 语句中可以使用 effectively-final 变量。

finalScannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))
try (scanner;writer) {
// omitted
}

什么是 effectively-final 变量? 简单来说就是没有被 final 修饰但是值在初始化后从未更改的变量。

正如上面的代码所演示的那样,即使 writer 变量没有被显示声明为 final,但它在第一次被复制后就不会改变了,因此,它就是 effectively-final 变量。

Stream & Optional 增强

Stream 中增加了新的方法 ofNullable()dropWhile()takeWhile() 以及 iterate() 方法的重载方法。

Java 9 中的 ofNullable() 方 法允许我们创建一个单元素的 Stream,可以包含一个非空元素,也可以创建一个空 Stream。 而在 Java 8 中则不可以创建空的 Stream

Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0

takeWhile() 方法可以从 Stream 中依次获取满足条件的元素,直到不满足条件为止结束获取。

List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33

dropWhile() 方法的效果和 takeWhile() 相反。

List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13

iterate() 方法的新重载方法提供了一个 Predicate 参数 (判断条件)来决定什么时候结束迭代

publicstatic<T> Stream<T> iterate(finalTseed, finalUnaryOperator<T> f) {
}
// 新增加的重载方法publicstatic<T> Stream<T> iterate(Tseed, Predicate<? superT> hasNext, UnaryOperator<T> next) {
}

两者的使用对比如下,新的 iterate() 重载方法更加灵活一些。

// 使用原始 iterate() 方法输出数字 1~10Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 使用新的 iterate() 重载方法输出数字 1~10Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);

Optional 类中新增了 ifPresentOrElse()or()stream() 等方法

ifPresentOrElse() 方法接受两个参数 ConsumerRunnable ,如果 Optional 不为空调用 Consumer 参数,为空则调用 Runnable 参数。

publicvoidifPresentOrElse(Consumer<? superT> action, RunnableemptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!

or() 方法接受一个 Supplier 参数 ,如果 Optional 为空则返回 Supplier 参数指定的 Optional 值。

publicOptional<T> or(Supplier<? extendsOptional<? extendsT>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//java

进程 API

Java 9 增加了 java.lang.ProcessHandle 接口来实现对原生进程进行管理,尤其适合于管理长时间运行的进程。

// 获取当前正在运行的 JVM 的进程ProcessHandlecurrentProcess = ProcessHandle.current();
// 输出进程的 idSystem.out.println(currentProcess.pid());
// 输出进程的信息System.out.println(currentProcess.info());

ProcessHandle 接口概览:

响应式流 ( Reactive Streams )

在 Java 9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口 。

Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

关于 Java 9 响应式流更详细的解读,推荐你看 Java 9 揭秘(17. Reactive Streams )- 林本托 这篇文章。

变量句柄

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。

变量句柄的含义类似于已有的方法句柄 MethodHandle ,由 Java 类 java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对象。

VarHandle 的出现替代了 java.util.concurrent.atomicsun.misc.Unsafe 的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的 API。

其它

  • 平台日志 API 改进 : Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
  • CompletableFuture类增强 :新增了几个新的方法(completeAsyncorTimeout 等)。
  • Nashorn 引擎的增强 :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性(Java 11 中已经被弃用)。
  • I/O 流的新特性 :增加了新的方法来读取和复制 InputStream 中包含的数据。
  • 改进应用的安全性能 :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。
  • 改进方法句柄(Method Handle) :方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄。
  • ......

参考

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

History
260 lines (177 loc) · 12 KB

File metadata and controls

260 lines (177 loc) · 12 KB
titleJava 9 新特性概览
categoryJava
tag
Java新特性

Java 9 发布于 2017 年 9 月 21 日 。作为 Java 8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流......。

你可以在 Archived OpenJDK General-Availability Releases 上下载自己需要的 JDK 版本!官方的新特性说明文档地址: https://openjdk.java.net/projects/jdk/

概览(精选了一部分)

JShell

JShell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。

在 JShell 中可以直接输入表达式并查看其执行结果。

JShell 为我们带来了哪些好处呢?

  1. 降低了输出第一行 Java 版"Hello World!"的门槛,能够提高新手的学习热情。
  2. 在处理简单的小逻辑,验证简单的小问题时,比 IDE 更有效率(并不是为了取代 IDE,对于复杂逻辑的验证,IDE 更合适,两者互补)。
  3. ......

JShell 的代码和普通的可编译代码,有什么不一样?

  1. 一旦语句输入完成,JShell 立即就能返回执行的结果,而不再需要编辑器、编译器、解释器。
  2. JShell 支持变量的重复声明,后面声明的会覆盖前面声明的。
  3. JShell 支持独立的表达式比如普通的加法运算 1 + 1
  4. ......

模块化系统

模块系统是Jigsaw Project的一部分,把模块化开发实践引入到了 Java 平台中,可以让我们的代码可重用性更好!

什么是模块系统? 官方的定义是:

A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor。

简单来说,你可以将一个模块看作是一组唯一命名、可重用的包、资源和模块描述文件(module-info.java)。

任意一个 jar 文件,只要加上一个模块描述文件(module-info.java),就可以升级为一个模块。

在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具 (Jlink 是随 Java 9 一起发布的新命令行工具。它允许开发人员为基于模块的 Java 应用程序创建自己的轻量级、定制的 JRE),创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。

我们可以通过 exports 关键词精准控制哪些类可以对外开放使用,哪些类只能内部使用。

modulemy.module {
//exports 公开指定包的所有公共成员exportscom.my.package.name;
}
modulemy.module {
//exports…to 限制访问的成员范围exportcommy.package.nametocom.specific.package;
}

想要深入了解 Java 9 的模块化,可以参考下面这几篇文章:

G1 成为默认垃圾回收器

在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。

G1 还是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。

快速创建不可变集合

增加了List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合(有点参考 Guava 的味道):

List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);

使用 of() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。

String 存储结构优化

Java 8 及之前的版本,String 一直是用 char[] 存储。在 Java 9 之后,String 的实现改用 byte[] 数组存储字符串,节省了空间。

publicfinalclassStringimplementsjava.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivatefinalbyte[] value;
}

接口私有方法

Java 9 允许在接口中使用私有方法。这样的话,接口的使用就更加灵活了,有点像是一个简化版的抽象类。

publicinterfaceMyInterface {
privatevoidmethodPrivate(){
}
}

try-with-resources 增强

在 Java 9 之前,我们只能在 try-with-resources 块中声明变量:

try (Scannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))) {
// omitted
}

在 Java 9 之后,在 try-with-resources 语句中可以使用 effectively-final 变量。

finalScannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))
try (scanner;writer) {
// omitted
}

什么是 effectively-final 变量? 简单来说就是没有被 final 修饰但是值在初始化后从未更改的变量。

正如上面的代码所演示的那样,即使 writer 变量没有被显示声明为 final,但它在第一次被复制后就不会改变了,因此,它就是 effectively-final 变量。

Stream & Optional 增强

Stream 中增加了新的方法 ofNullable()dropWhile()takeWhile() 以及 iterate() 方法的重载方法。

Java 9 中的 ofNullable() 方 法允许我们创建一个单元素的 Stream,可以包含一个非空元素,也可以创建一个空 Stream。 而在 Java 8 中则不可以创建空的 Stream

Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0

takeWhile() 方法可以从 Stream 中依次获取满足条件的元素,直到不满足条件为止结束获取。

List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33

dropWhile() 方法的效果和 takeWhile() 相反。

List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13

iterate() 方法的新重载方法提供了一个 Predicate 参数 (判断条件)来决定什么时候结束迭代

publicstatic<T> Stream<T> iterate(finalTseed, finalUnaryOperator<T> f) {
}
// 新增加的重载方法publicstatic<T> Stream<T> iterate(Tseed, Predicate<? superT> hasNext, UnaryOperator<T> next) {
}

两者的使用对比如下,新的 iterate() 重载方法更加灵活一些。

// 使用原始 iterate() 方法输出数字 1~10Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 使用新的 iterate() 重载方法输出数字 1~10Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);

Optional 类中新增了 ifPresentOrElse()or()stream() 等方法

ifPresentOrElse() 方法接受两个参数 ConsumerRunnable ,如果 Optional 不为空调用 Consumer 参数,为空则调用 Runnable 参数。

publicvoidifPresentOrElse(Consumer<? superT> action, RunnableemptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!

or() 方法接受一个 Supplier 参数 ,如果 Optional 为空则返回 Supplier 参数指定的 Optional 值。

publicOptional<T> or(Supplier<? extendsOptional<? extendsT>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//java

进程 API

Java 9 增加了 java.lang.ProcessHandle 接口来实现对原生进程进行管理,尤其适合于管理长时间运行的进程。

// 获取当前正在运行的 JVM 的进程ProcessHandlecurrentProcess = ProcessHandle.current();
// 输出进程的 idSystem.out.println(currentProcess.pid());
// 输出进程的信息System.out.println(currentProcess.info());

ProcessHandle 接口概览:

响应式流 ( Reactive Streams )

在 Java 9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口 。

Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

关于 Java 9 响应式流更详细的解读,推荐你看 Java 9 揭秘(17. Reactive Streams )- 林本托 这篇文章。

变量句柄

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。

变量句柄的含义类似于已有的方法句柄 MethodHandle ,由 Java 类 java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对象。

VarHandle 的出现替代了 java.util.concurrent.atomicsun.misc.Unsafe 的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的 API。

其它

  • 平台日志 API 改进 : Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
  • CompletableFuture类增强 :新增了几个新的方法(completeAsyncorTimeout 等)。
  • Nashorn 引擎的增强 :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性(Java 11 中已经被弃用)。
  • I/O 流的新特性 :增加了新的方法来读取和复制 InputStream 中包含的数据。
  • 改进应用的安全性能 :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。
  • 改进方法句柄(Method Handle) :方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄。
  • ......

参考

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

History
260 lines (177 loc) · 12 KB

File metadata and controls

260 lines (177 loc) · 12 KB
titleJava 9 新特性概览
categoryJava
tag
Java新特性

Java 9 发布于 2017 年 9 月 21 日 。作为 Java 8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流......。

你可以在 Archived OpenJDK General-Availability Releases 上下载自己需要的 JDK 版本!官方的新特性说明文档地址: https://openjdk.java.net/projects/jdk/

概览(精选了一部分)

JShell

JShell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。

在 JShell 中可以直接输入表达式并查看其执行结果。

JShell 为我们带来了哪些好处呢?

  1. 降低了输出第一行 Java 版"Hello World!"的门槛,能够提高新手的学习热情。
  2. 在处理简单的小逻辑,验证简单的小问题时,比 IDE 更有效率(并不是为了取代 IDE,对于复杂逻辑的验证,IDE 更合适,两者互补)。
  3. ......

JShell 的代码和普通的可编译代码,有什么不一样?

  1. 一旦语句输入完成,JShell 立即就能返回执行的结果,而不再需要编辑器、编译器、解释器。
  2. JShell 支持变量的重复声明,后面声明的会覆盖前面声明的。
  3. JShell 支持独立的表达式比如普通的加法运算 1 + 1
  4. ......

模块化系统

模块系统是Jigsaw Project的一部分,把模块化开发实践引入到了 Java 平台中,可以让我们的代码可重用性更好!

什么是模块系统? 官方的定义是:

A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor。

简单来说,你可以将一个模块看作是一组唯一命名、可重用的包、资源和模块描述文件(module-info.java)。

任意一个 jar 文件,只要加上一个模块描述文件(module-info.java),就可以升级为一个模块。

在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具 (Jlink 是随 Java 9 一起发布的新命令行工具。它允许开发人员为基于模块的 Java 应用程序创建自己的轻量级、定制的 JRE),创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。

我们可以通过 exports 关键词精准控制哪些类可以对外开放使用,哪些类只能内部使用。

modulemy.module {
//exports 公开指定包的所有公共成员exportscom.my.package.name;
}
modulemy.module {
//exports…to 限制访问的成员范围exportcommy.package.nametocom.specific.package;
}

想要深入了解 Java 9 的模块化,可以参考下面这几篇文章:

G1 成为默认垃圾回收器

在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。

G1 还是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。

快速创建不可变集合

增加了List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合(有点参考 Guava 的味道):

List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);

使用 of() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。

String 存储结构优化

Java 8 及之前的版本,String 一直是用 char[] 存储。在 Java 9 之后,String 的实现改用 byte[] 数组存储字符串,节省了空间。

publicfinalclassStringimplementsjava.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivatefinalbyte[] value;
}

接口私有方法

Java 9 允许在接口中使用私有方法。这样的话,接口的使用就更加灵活了,有点像是一个简化版的抽象类。

publicinterfaceMyInterface {
privatevoidmethodPrivate(){
}
}

try-with-resources 增强

在 Java 9 之前,我们只能在 try-with-resources 块中声明变量:

try (Scannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))) {
// omitted
}

在 Java 9 之后,在 try-with-resources 语句中可以使用 effectively-final 变量。

finalScannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))
try (scanner;writer) {
// omitted
}

什么是 effectively-final 变量? 简单来说就是没有被 final 修饰但是值在初始化后从未更改的变量。

正如上面的代码所演示的那样,即使 writer 变量没有被显示声明为 final,但它在第一次被复制后就不会改变了,因此,它就是 effectively-final 变量。

Stream & Optional 增强

Stream 中增加了新的方法 ofNullable()dropWhile()takeWhile() 以及 iterate() 方法的重载方法。

Java 9 中的 ofNullable() 方 法允许我们创建一个单元素的 Stream,可以包含一个非空元素,也可以创建一个空 Stream。 而在 Java 8 中则不可以创建空的 Stream

Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0

takeWhile() 方法可以从 Stream 中依次获取满足条件的元素,直到不满足条件为止结束获取。

List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33

dropWhile() 方法的效果和 takeWhile() 相反。

List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13

iterate() 方法的新重载方法提供了一个 Predicate 参数 (判断条件)来决定什么时候结束迭代

publicstatic<T> Stream<T> iterate(finalTseed, finalUnaryOperator<T> f) {
}
// 新增加的重载方法publicstatic<T> Stream<T> iterate(Tseed, Predicate<? superT> hasNext, UnaryOperator<T> next) {
}

两者的使用对比如下,新的 iterate() 重载方法更加灵活一些。

// 使用原始 iterate() 方法输出数字 1~10Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 使用新的 iterate() 重载方法输出数字 1~10Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);

Optional 类中新增了 ifPresentOrElse()or()stream() 等方法

ifPresentOrElse() 方法接受两个参数 ConsumerRunnable ,如果 Optional 不为空调用 Consumer 参数,为空则调用 Runnable 参数。

publicvoidifPresentOrElse(Consumer<? superT> action, RunnableemptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!

or() 方法接受一个 Supplier 参数 ,如果 Optional 为空则返回 Supplier 参数指定的 Optional 值。

publicOptional<T> or(Supplier<? extendsOptional<? extendsT>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//java

进程 API

Java 9 增加了 java.lang.ProcessHandle 接口来实现对原生进程进行管理,尤其适合于管理长时间运行的进程。

// 获取当前正在运行的 JVM 的进程ProcessHandlecurrentProcess = ProcessHandle.current();
// 输出进程的 idSystem.out.println(currentProcess.pid());
// 输出进程的信息System.out.println(currentProcess.info());

ProcessHandle 接口概览:

响应式流 ( Reactive Streams )

在 Java 9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口 。

Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

关于 Java 9 响应式流更详细的解读,推荐你看 Java 9 揭秘(17. Reactive Streams )- 林本托 这篇文章。

变量句柄

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。

变量句柄的含义类似于已有的方法句柄 MethodHandle ,由 Java 类 java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对象。

VarHandle 的出现替代了 java.util.concurrent.atomicsun.misc.Unsafe 的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的 API。

其它

  • 平台日志 API 改进 : Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
  • CompletableFuture类增强 :新增了几个新的方法(completeAsyncorTimeout 等)。
  • Nashorn 引擎的增强 :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性(Java 11 中已经被弃用)。
  • I/O 流的新特性 :增加了新的方法来读取和复制 InputStream 中包含的数据。
  • 改进应用的安全性能 :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。
  • 改进方法句柄(Method Handle) :方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄。
  • ......

参考

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

History
260 lines (177 loc) · 12 KB

File metadata and controls

260 lines (177 loc) · 12 KB
titleJava 9 新特性概览
categoryJava
tag
Java新特性

Java 9 发布于 2017 年 9 月 21 日 。作为 Java 8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流......。

你可以在 Archived OpenJDK General-Availability Releases 上下载自己需要的 JDK 版本!官方的新特性说明文档地址: https://openjdk.java.net/projects/jdk/

概览(精选了一部分)

JShell

JShell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。

在 JShell 中可以直接输入表达式并查看其执行结果。

JShell 为我们带来了哪些好处呢?

  1. 降低了输出第一行 Java 版"Hello World!"的门槛,能够提高新手的学习热情。
  2. 在处理简单的小逻辑,验证简单的小问题时,比 IDE 更有效率(并不是为了取代 IDE,对于复杂逻辑的验证,IDE 更合适,两者互补)。
  3. ......

JShell 的代码和普通的可编译代码,有什么不一样?

  1. 一旦语句输入完成,JShell 立即就能返回执行的结果,而不再需要编辑器、编译器、解释器。
  2. JShell 支持变量的重复声明,后面声明的会覆盖前面声明的。
  3. JShell 支持独立的表达式比如普通的加法运算 1 + 1
  4. ......

模块化系统

模块系统是Jigsaw Project的一部分,把模块化开发实践引入到了 Java 平台中,可以让我们的代码可重用性更好!

什么是模块系统? 官方的定义是:

A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor。

简单来说,你可以将一个模块看作是一组唯一命名、可重用的包、资源和模块描述文件(module-info.java)。

任意一个 jar 文件,只要加上一个模块描述文件(module-info.java),就可以升级为一个模块。

在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具 (Jlink 是随 Java 9 一起发布的新命令行工具。它允许开发人员为基于模块的 Java 应用程序创建自己的轻量级、定制的 JRE),创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。

我们可以通过 exports 关键词精准控制哪些类可以对外开放使用,哪些类只能内部使用。

modulemy.module {
//exports 公开指定包的所有公共成员exportscom.my.package.name;
}
modulemy.module {
//exports…to 限制访问的成员范围exportcommy.package.nametocom.specific.package;
}

想要深入了解 Java 9 的模块化,可以参考下面这几篇文章:

G1 成为默认垃圾回收器

在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。

G1 还是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。

快速创建不可变集合

增加了List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合(有点参考 Guava 的味道):

List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);

使用 of() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。

String 存储结构优化

Java 8 及之前的版本,String 一直是用 char[] 存储。在 Java 9 之后,String 的实现改用 byte[] 数组存储字符串,节省了空间。

publicfinalclassStringimplementsjava.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivatefinalbyte[] value;
}

接口私有方法

Java 9 允许在接口中使用私有方法。这样的话,接口的使用就更加灵活了,有点像是一个简化版的抽象类。

publicinterfaceMyInterface {
privatevoidmethodPrivate(){
}
}

try-with-resources 增强

在 Java 9 之前,我们只能在 try-with-resources 块中声明变量:

try (Scannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))) {
// omitted
}

在 Java 9 之后,在 try-with-resources 语句中可以使用 effectively-final 变量。

finalScannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))
try (scanner;writer) {
// omitted
}

什么是 effectively-final 变量? 简单来说就是没有被 final 修饰但是值在初始化后从未更改的变量。

正如上面的代码所演示的那样,即使 writer 变量没有被显示声明为 final,但它在第一次被复制后就不会改变了,因此,它就是 effectively-final 变量。

Stream & Optional 增强

Stream 中增加了新的方法 ofNullable()dropWhile()takeWhile() 以及 iterate() 方法的重载方法。

Java 9 中的 ofNullable() 方 法允许我们创建一个单元素的 Stream,可以包含一个非空元素,也可以创建一个空 Stream。 而在 Java 8 中则不可以创建空的 Stream

Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0

takeWhile() 方法可以从 Stream 中依次获取满足条件的元素,直到不满足条件为止结束获取。

List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33

dropWhile() 方法的效果和 takeWhile() 相反。

List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13

iterate() 方法的新重载方法提供了一个 Predicate 参数 (判断条件)来决定什么时候结束迭代

publicstatic<T> Stream<T> iterate(finalTseed, finalUnaryOperator<T> f) {
}
// 新增加的重载方法publicstatic<T> Stream<T> iterate(Tseed, Predicate<? superT> hasNext, UnaryOperator<T> next) {
}

两者的使用对比如下,新的 iterate() 重载方法更加灵活一些。

// 使用原始 iterate() 方法输出数字 1~10Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 使用新的 iterate() 重载方法输出数字 1~10Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);

Optional 类中新增了 ifPresentOrElse()or()stream() 等方法

ifPresentOrElse() 方法接受两个参数 ConsumerRunnable ,如果 Optional 不为空调用 Consumer 参数,为空则调用 Runnable 参数。

publicvoidifPresentOrElse(Consumer<? superT> action, RunnableemptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!

or() 方法接受一个 Supplier 参数 ,如果 Optional 为空则返回 Supplier 参数指定的 Optional 值。

publicOptional<T> or(Supplier<? extendsOptional<? extendsT>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//java

进程 API

Java 9 增加了 java.lang.ProcessHandle 接口来实现对原生进程进行管理,尤其适合于管理长时间运行的进程。

// 获取当前正在运行的 JVM 的进程ProcessHandlecurrentProcess = ProcessHandle.current();
// 输出进程的 idSystem.out.println(currentProcess.pid());
// 输出进程的信息System.out.println(currentProcess.info());

ProcessHandle 接口概览:

响应式流 ( Reactive Streams )

在 Java 9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口 。

Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

关于 Java 9 响应式流更详细的解读,推荐你看 Java 9 揭秘(17. Reactive Streams )- 林本托 这篇文章。

变量句柄

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。

变量句柄的含义类似于已有的方法句柄 MethodHandle ,由 Java 类 java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对象。

VarHandle 的出现替代了 java.util.concurrent.atomicsun.misc.Unsafe 的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的 API。

其它

  • 平台日志 API 改进 : Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
  • CompletableFuture类增强 :新增了几个新的方法(completeAsyncorTimeout 等)。
  • Nashorn 引擎的增强 :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性(Java 11 中已经被弃用)。
  • I/O 流的新特性 :增加了新的方法来读取和复制 InputStream 中包含的数据。
  • 改进应用的安全性能 :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。
  • 改进方法句柄(Method Handle) :方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄。
  • ......

参考

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

History
260 lines (177 loc) · 12 KB

File metadata and controls

260 lines (177 loc) · 12 KB
titleJava 9 新特性概览
categoryJava
tag
Java新特性

Java 9 发布于 2017 年 9 月 21 日 。作为 Java 8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流......。

你可以在 Archived OpenJDK General-Availability Releases 上下载自己需要的 JDK 版本!官方的新特性说明文档地址: https://openjdk.java.net/projects/jdk/

概览(精选了一部分)

JShell

JShell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。

在 JShell 中可以直接输入表达式并查看其执行结果。

JShell 为我们带来了哪些好处呢?

  1. 降低了输出第一行 Java 版"Hello World!"的门槛,能够提高新手的学习热情。
  2. 在处理简单的小逻辑,验证简单的小问题时,比 IDE 更有效率(并不是为了取代 IDE,对于复杂逻辑的验证,IDE 更合适,两者互补)。
  3. ......

JShell 的代码和普通的可编译代码,有什么不一样?

  1. 一旦语句输入完成,JShell 立即就能返回执行的结果,而不再需要编辑器、编译器、解释器。
  2. JShell 支持变量的重复声明,后面声明的会覆盖前面声明的。
  3. JShell 支持独立的表达式比如普通的加法运算 1 + 1
  4. ......

模块化系统

模块系统是Jigsaw Project的一部分,把模块化开发实践引入到了 Java 平台中,可以让我们的代码可重用性更好!

什么是模块系统? 官方的定义是:

A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor。

简单来说,你可以将一个模块看作是一组唯一命名、可重用的包、资源和模块描述文件(module-info.java)。

任意一个 jar 文件,只要加上一个模块描述文件(module-info.java),就可以升级为一个模块。

在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具 (Jlink 是随 Java 9 一起发布的新命令行工具。它允许开发人员为基于模块的 Java 应用程序创建自己的轻量级、定制的 JRE),创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。

我们可以通过 exports 关键词精准控制哪些类可以对外开放使用,哪些类只能内部使用。

modulemy.module {
//exports 公开指定包的所有公共成员exportscom.my.package.name;
}
modulemy.module {
//exports…to 限制访问的成员范围exportcommy.package.nametocom.specific.package;
}

想要深入了解 Java 9 的模块化,可以参考下面这几篇文章:

G1 成为默认垃圾回收器

在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。

G1 还是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。

快速创建不可变集合

增加了List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合(有点参考 Guava 的味道):

List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);

使用 of() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。

String 存储结构优化

Java 8 及之前的版本,String 一直是用 char[] 存储。在 Java 9 之后,String 的实现改用 byte[] 数组存储字符串,节省了空间。

publicfinalclassStringimplementsjava.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivatefinalbyte[] value;
}

接口私有方法

Java 9 允许在接口中使用私有方法。这样的话,接口的使用就更加灵活了,有点像是一个简化版的抽象类。

publicinterfaceMyInterface {
privatevoidmethodPrivate(){
}
}

try-with-resources 增强

在 Java 9 之前,我们只能在 try-with-resources 块中声明变量:

try (Scannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))) {
// omitted
}

在 Java 9 之后,在 try-with-resources 语句中可以使用 effectively-final 变量。

finalScannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))
try (scanner;writer) {
// omitted
}

什么是 effectively-final 变量? 简单来说就是没有被 final 修饰但是值在初始化后从未更改的变量。

正如上面的代码所演示的那样,即使 writer 变量没有被显示声明为 final,但它在第一次被复制后就不会改变了,因此,它就是 effectively-final 变量。

Stream & Optional 增强

Stream 中增加了新的方法 ofNullable()dropWhile()takeWhile() 以及 iterate() 方法的重载方法。

Java 9 中的 ofNullable() 方 法允许我们创建一个单元素的 Stream,可以包含一个非空元素,也可以创建一个空 Stream。 而在 Java 8 中则不可以创建空的 Stream

Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0

takeWhile() 方法可以从 Stream 中依次获取满足条件的元素,直到不满足条件为止结束获取。

List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33

dropWhile() 方法的效果和 takeWhile() 相反。

List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13

iterate() 方法的新重载方法提供了一个 Predicate 参数 (判断条件)来决定什么时候结束迭代

publicstatic<T> Stream<T> iterate(finalTseed, finalUnaryOperator<T> f) {
}
// 新增加的重载方法publicstatic<T> Stream<T> iterate(Tseed, Predicate<? superT> hasNext, UnaryOperator<T> next) {
}

两者的使用对比如下,新的 iterate() 重载方法更加灵活一些。

// 使用原始 iterate() 方法输出数字 1~10Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 使用新的 iterate() 重载方法输出数字 1~10Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);

Optional 类中新增了 ifPresentOrElse()or()stream() 等方法

ifPresentOrElse() 方法接受两个参数 ConsumerRunnable ,如果 Optional 不为空调用 Consumer 参数,为空则调用 Runnable 参数。

publicvoidifPresentOrElse(Consumer<? superT> action, RunnableemptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!

or() 方法接受一个 Supplier 参数 ,如果 Optional 为空则返回 Supplier 参数指定的 Optional 值。

publicOptional<T> or(Supplier<? extendsOptional<? extendsT>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//java

进程 API

Java 9 增加了 java.lang.ProcessHandle 接口来实现对原生进程进行管理,尤其适合于管理长时间运行的进程。

// 获取当前正在运行的 JVM 的进程ProcessHandlecurrentProcess = ProcessHandle.current();
// 输出进程的 idSystem.out.println(currentProcess.pid());
// 输出进程的信息System.out.println(currentProcess.info());

ProcessHandle 接口概览:

响应式流 ( Reactive Streams )

在 Java 9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口 。

Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

关于 Java 9 响应式流更详细的解读,推荐你看 Java 9 揭秘(17. Reactive Streams )- 林本托 这篇文章。

变量句柄

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。

变量句柄的含义类似于已有的方法句柄 MethodHandle ,由 Java 类 java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对象。

VarHandle 的出现替代了 java.util.concurrent.atomicsun.misc.Unsafe 的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的 API。

其它

  • 平台日志 API 改进 : Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
  • CompletableFuture类增强 :新增了几个新的方法(completeAsyncorTimeout 等)。
  • Nashorn 引擎的增强 :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性(Java 11 中已经被弃用)。
  • I/O 流的新特性 :增加了新的方法来读取和复制 InputStream 中包含的数据。
  • 改进应用的安全性能 :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。
  • 改进方法句柄(Method Handle) :方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄。
  • ......

参考

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

History
260 lines (177 loc) · 12 KB

File metadata and controls

260 lines (177 loc) · 12 KB
titleJava 9 新特性概览
categoryJava
tag
Java新特性

Java 9 发布于 2017 年 9 月 21 日 。作为 Java 8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流......。

你可以在 Archived OpenJDK General-Availability Releases 上下载自己需要的 JDK 版本!官方的新特性说明文档地址: https://openjdk.java.net/projects/jdk/

概览(精选了一部分)

JShell

JShell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。

在 JShell 中可以直接输入表达式并查看其执行结果。

JShell 为我们带来了哪些好处呢?

  1. 降低了输出第一行 Java 版"Hello World!"的门槛,能够提高新手的学习热情。
  2. 在处理简单的小逻辑,验证简单的小问题时,比 IDE 更有效率(并不是为了取代 IDE,对于复杂逻辑的验证,IDE 更合适,两者互补)。
  3. ......

JShell 的代码和普通的可编译代码,有什么不一样?

  1. 一旦语句输入完成,JShell 立即就能返回执行的结果,而不再需要编辑器、编译器、解释器。
  2. JShell 支持变量的重复声明,后面声明的会覆盖前面声明的。
  3. JShell 支持独立的表达式比如普通的加法运算 1 + 1
  4. ......

模块化系统

模块系统是Jigsaw Project的一部分,把模块化开发实践引入到了 Java 平台中,可以让我们的代码可重用性更好!

什么是模块系统? 官方的定义是:

A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor。

简单来说,你可以将一个模块看作是一组唯一命名、可重用的包、资源和模块描述文件(module-info.java)。

任意一个 jar 文件,只要加上一个模块描述文件(module-info.java),就可以升级为一个模块。

在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具 (Jlink 是随 Java 9 一起发布的新命令行工具。它允许开发人员为基于模块的 Java 应用程序创建自己的轻量级、定制的 JRE),创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。

我们可以通过 exports 关键词精准控制哪些类可以对外开放使用,哪些类只能内部使用。

modulemy.module {
//exports 公开指定包的所有公共成员exportscom.my.package.name;
}
modulemy.module {
//exports…to 限制访问的成员范围exportcommy.package.nametocom.specific.package;
}

想要深入了解 Java 9 的模块化,可以参考下面这几篇文章:

G1 成为默认垃圾回收器

在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。

G1 还是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。

快速创建不可变集合

增加了List.of()Set.of()Map.of()Map.ofEntries()等工厂方法来创建不可变集合(有点参考 Guava 的味道):

List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);

使用 of() 创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。

String 存储结构优化

Java 8 及之前的版本,String 一直是用 char[] 存储。在 Java 9 之后,String 的实现改用 byte[] 数组存储字符串,节省了空间。

publicfinalclassStringimplementsjava.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivatefinalbyte[] value;
}

接口私有方法

Java 9 允许在接口中使用私有方法。这样的话,接口的使用就更加灵活了,有点像是一个简化版的抽象类。

publicinterfaceMyInterface {
privatevoidmethodPrivate(){
}
}

try-with-resources 增强

在 Java 9 之前,我们只能在 try-with-resources 块中声明变量:

try (Scannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))) {
// omitted
}

在 Java 9 之后,在 try-with-resources 语句中可以使用 effectively-final 变量。

finalScannerscanner = newScanner(newFile("testRead.txt"));
PrintWriterwriter = newPrintWriter(newFile("testWrite.txt"))
try (scanner;writer) {
// omitted
}

什么是 effectively-final 变量? 简单来说就是没有被 final 修饰但是值在初始化后从未更改的变量。

正如上面的代码所演示的那样,即使 writer 变量没有被显示声明为 final,但它在第一次被复制后就不会改变了,因此,它就是 effectively-final 变量。

Stream & Optional 增强

Stream 中增加了新的方法 ofNullable()dropWhile()takeWhile() 以及 iterate() 方法的重载方法。

Java 9 中的 ofNullable() 方 法允许我们创建一个单元素的 Stream,可以包含一个非空元素,也可以创建一个空 Stream。 而在 Java 8 中则不可以创建空的 Stream

Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0

takeWhile() 方法可以从 Stream 中依次获取满足条件的元素,直到不满足条件为止结束获取。

List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33

dropWhile() 方法的效果和 takeWhile() 相反。

List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13

iterate() 方法的新重载方法提供了一个 Predicate 参数 (判断条件)来决定什么时候结束迭代

publicstatic<T> Stream<T> iterate(finalTseed, finalUnaryOperator<T> f) {
}
// 新增加的重载方法publicstatic<T> Stream<T> iterate(Tseed, Predicate<? superT> hasNext, UnaryOperator<T> next) {
}

两者的使用对比如下,新的 iterate() 重载方法更加灵活一些。

// 使用原始 iterate() 方法输出数字 1~10Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 使用新的 iterate() 重载方法输出数字 1~10Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);

Optional 类中新增了 ifPresentOrElse()or()stream() 等方法

ifPresentOrElse() 方法接受两个参数 ConsumerRunnable ,如果 Optional 不为空调用 Consumer 参数,为空则调用 Runnable 参数。

publicvoidifPresentOrElse(Consumer<? superT> action, RunnableemptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!

or() 方法接受一个 Supplier 参数 ,如果 Optional 为空则返回 Supplier 参数指定的 Optional 值。

publicOptional<T> or(Supplier<? extendsOptional<? extendsT>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//java

进程 API

Java 9 增加了 java.lang.ProcessHandle 接口来实现对原生进程进行管理,尤其适合于管理长时间运行的进程。

// 获取当前正在运行的 JVM 的进程ProcessHandlecurrentProcess = ProcessHandle.current();
// 输出进程的 idSystem.out.println(currentProcess.pid());
// 输出进程的信息System.out.println(currentProcess.info());

ProcessHandle 接口概览:

响应式流 ( Reactive Streams )

在 Java 9 中的 java.util.concurrent.Flow 类中新增了反应式流规范的核心接口 。

Flow 中包含了 Flow.PublisherFlow.SubscriberFlow.SubscriptionFlow.Processor 等 4 个核心接口。Java 9 还提供了SubmissionPublisher 作为Flow.Publisher 的一个实现。

关于 Java 9 响应式流更详细的解读,推荐你看 Java 9 揭秘(17. Reactive Streams )- 林本托 这篇文章。

变量句柄

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。

变量句柄的含义类似于已有的方法句柄 MethodHandle ,由 Java 类 java.lang.invoke.VarHandle 来表示,可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对象。

VarHandle 的出现替代了 java.util.concurrent.atomicsun.misc.Unsafe 的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的 API。

其它

  • 平台日志 API 改进 : Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
  • CompletableFuture类增强 :新增了几个新的方法(completeAsyncorTimeout 等)。
  • Nashorn 引擎的增强 :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性(Java 11 中已经被弃用)。
  • I/O 流的新特性 :增加了新的方法来读取和复制 InputStream 中包含的数据。
  • 改进应用的安全性能 :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。
  • 改进方法句柄(Method Handle) :方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄。
  • ......

参考