点击上方 “未读代码” 关注我,不断推送原创文章与你分享。

Java 新特性系列已经从 Java 7 开始补充到 Java 9 了,每一篇的反馈都还不错。这个系列会持续更新到 Java 13 版本,然后在每个 Java 新版本发布时同步更新这个系列。你可以在文末找到这个系列的其他文章。

Java 9 中最大的亮点是 Java 平台模块化的引入,以及模块化 JDK。但是 Java 9 还有很多其他新功能,这篇文字会将重点介绍开发人员特别感兴趣的几种功能。

1.  模块化

Java 9 中的模块化是对 Java 的一次重大改进。但是模块化并不是最近才提出来的,我们经常使用的  maven 构建工具,就是典型的模块化构建工具。模块化不仅让模块命名清晰,写出高内聚低耦合的代码,更可以方便处理模块之间的调用关系。

Java 9 模块系统

在 Oracle 官方中为 Java 9 中的模块系统的定义如下:

the module, which is a named, self-describing collection of code and data. This module system.

直白翻译:模块是一个命名的,自我描述的代码和数据的集合。

Java 9 不仅支持了模块化开发,更是直接把 JDK 自身进行了模块化处理。JDK 自身的模块化可以带来很多好处,比如:

  • 方便管理,越来越大的 JDK 在模块化下结构变得更加清晰。
  • 模块化 JDK 和 JRE 运行时镜像可以提高性能、安全性、维护性。
  • 可以定制 JRE,使用更小的运行时镜像,比如网络应用不需要 swing 库,可以在打包时选择不用,减少性能消耗。
  • 清晰明了的模块调用关系,避免调用不当出来的各种问题。

上面提到了 JDK 自身的模块化,我们通过浏览 JDK 9 的目录结构也可以发现一些变化。

JDK 模块化

最明显的是在 JDK 9 中 jre 文件夹不存在了。下面是在 IDEA 中查看的 JDK 9 的依赖,命名规范的模块看起来是不是让人赏心悦目呢?

JDK 9 在 DEA (这里我放错图了,微信不支持改图)

当然,这篇文章主要介绍 Java 9 的新特性,而模块化是一个巨大改变,结合示例介绍下来篇幅会比较长,这里就不占用太多篇幅了。

模块化文章预告:如何编写一个模块化系统,如何打包让没有安装 Java 环境的系统运行编写的代码,都可以通过模块化选择运行时模块实现。我后面的文章就会通过一个模块化项目介绍到,有兴趣的可以关注我后续文章 ?。

2. 集合工厂方法

在 Java 9 中为集合的创建增加了静态工厂创建方式,也就是 of 方法,通过静态工厂 of 方法创建的集合是只读集合,里面的对象不可改变。并在不能存在 null,对于 setmap 集合,也不能存在 key 值重复。这样不仅线程安全,而且消耗的内存也更小

下面是三种集合通过静态工厂创建的方式。

// 工厂方法创建集合List stringList = List.of("a", "b", "c", "d");Set stringSet = Set.of("a", "b", "c", "d");Map stringIntegerMap = Map.of("key1", 1, "key2", 2, "key3", 3);Map stringIntegerMap2 = Map.ofEntries(Map.entry("key1", 1), Map.entry("key2", 2));// 集合输出System.out.println(stringList);System.out.println(stringSet);System.out.println(stringIntegerMap);System.out.println(stringIntegerMap2);

得到输出结果。

[a, b, c, d][d, a, c, b]{key2=2, key1=1, key3=3}{key2=2, key1=1}

再次运行,得到输出结果。

[a, b, c, d][a, c, b, d]{key3=3, key2=2, key1=1}{key2=2, key1=1}

为什么我贴了两次运行结果呢?主要是要展示通过 of 方法创建的 setmap 集合在遍历时,在每个 JVM 周期遍历顺序是随机的,这样的机制可以发下代码中有没有对于顺序敏感的异常代码。

这种只读集合在 Java 9 之前创建是通过 Collections.unmodifiableList 修改集合操作权限实现的。

List arrayList = new ArrayList<>();arrayList.add("达西");arrayList.add("未读代码");// 设置为只读集合arrayList = Collections.unmodifiableList(arrayList);

静态工厂 of 方法创建的集合还有一个特性,就是工厂内部会自由复用已有实例或者创建新的实例,所以应该避免对 of 创建的集合进行判等或者 haseCode 比较等操作。

像下面这样,创建两个 List,你会发现两个 ListhashCode 是一样的。

// 工厂可以自由创建新的实例或者复用现有实例,所以 使用 of 创建的集合,避免 == 或者 hashCode 判断操作List stringList = List.of("a", "b", "c", "d");List stringList2 = List.of("a", "b", "c", "d");System.out.println(stringList.hashCode());System.out.println(stringList2.hashCode());// 输出结果// 3910595// 3910596

这也是使用 of 方法创建集合的优势之一,消耗更少的系统资源。这一点也体现在 of 创建的集合的数据结构实现上,有兴趣的同学可以自行研究下。

3. Stream API

Stream 流操作自从 Java 8 引入以来,一直广受好评。便捷丰富的 Stream 操作让人爱不释手,更让没看过的同事眼花缭乱,在介绍 Java 8 新特性时已经对 Stream 进行了详细的介绍,没看过的同学可以看下这篇:

还看不懂同事的代码?超强的 Stream 流操作姿势还不学习一下

当然,学习 Stream 之前要先学习 Lambda ,如果你还没有看过,也可以看下之前这篇:

还看不懂同事的代码?Lambda 表达式、函数接口了解一下

Java 9 中,又对 Stream 进行了增强,主要增加了 4 个新的操作方法:dropWhile,takeWhile,ofNullable,iterate

下面对这几个方法分别做个介绍。

  1. takeWhile: 从头开始筛选,遇到不满足的就结束了。

    // takeWhile ,从头开始筛选,遇到不满足的就结束了List list1 = List.of(1, 2, 3, 4, 5);List listResult = list1.stream().takeWhile(x -> x < 3).collect(Collectors.toList());System.out.println(listResult);// takeWhile ,从头开始筛选,遇到不满足的就结束List list2 = List.of(1, 2, 3, 4, 3, 0);List listResult2 = list2.stream().takeWhile(x -> x < 3).collect(Collectors.toList());System.out.println(listResult2);

    输出结果。

    [1, 2][1, 2]
  2. dropWhile: 从头开始删除,遇到不满足的就结束了。

    // dropWhile ,从头开始删除,遇到不满足的就结束了List list1 = List.of(1, 2, 3, 4, 5);List listResult = list1.stream().dropWhile(x -> x < 3).collect(Collectors.toList());System.out.println(listResult);// dropWhile ,从头开始删除,遇到不满足的就结束List list2 = List.of(1, 2, 3, 4, 3, 0);List listResult2 = list2.stream().dropWhile(x -> x < 3).collect(Collectors.toList());System.out.println(listResult2);

    输出结果。

    [3, 4, 5][3, 4, 3, 0]
  3. ofNullable: 创建支持全 null 的 Stream.

    Stream stream = Stream.of(1, 2, null);stream.forEach(System.out::print);System.out.println();// 空指针异常// stream = Stream.of(null);stream = Stream.ofNullable(null);stream.forEach(System.out::print);

    输出结果。

    12null
  4. iterate: 可以重载迭代器。

    IntStream.iterate(0, x -> x < 10, x -> x + 1).forEach(System.out::print);

    输出结果。

    0123456789

Stream 增强之外,还增强了 OptionalOptional 增加了可以转换成 Stream 的方法。

Stream s = Optional.of(1).stream();s.forEach(System.out::print);

4. 接口私有方法

Java 8 中增加了默认方法,在 Java 9 中又增加了私有方法,这时开始接口中不仅仅有了定义,还具有了行为。我想这是出于代码构造上的考虑,如果没有私有方法,那么当多个默认方法的行为一样时,就要写多个相同的代码。而有了私有方法,事情就变得不一样了。

就像下面的例子。

/** * @author 达西 - 公众号:未读代码 */public class Jdk9Interface {public static void main(String[] args) {        ChinaPeople chinaPeople = new ChinaPeople();        chinaPeople.sleep();        chinaPeople.eat();        chinaPeople.doXxx();    }

}

class ChinaPeople implements People {@Overridepublic void sleep() {        System.out.println("躺着睡");    }}

interface People {void sleep();

default void eat() {        drink();    }

default void doXxx() {        drink();    }

private void drink() {        System.out.println("喝水");    }}

例子中的接口 people 中的 eat()doXxx() 默认行为一致,使用私有方法可以方便的抽取一个方法出来。

输出结果。

躺着睡喝水喝水

5. HTTP / 2 Client

Java 9 内置了新的 HTTP/2 客户端,请求更加方便。

随便访问一个不存在的网页。

HttpClient client = HttpClient.newHttpClient();URI uri = URI.create("http://www.tianqiapi.com/api/xxx");HttpRequest req = HttpRequest.newBuilder(uri).header("User-Agent", "Java").GET().build();HttpResponse resp = client.send(req, HttpResponse.BodyHandler.asString());String body = resp.body();System.out.println(body);

输出得到的结果,这里是这个网站的报错信息。

There is no method xxxAction in ApiController

可能你运行的时候会报找不到 httpClient 模块之类的问题,这时候需要你在你项目代码目录添加 httpClient 模块 才能解决,添加方式看下面的图。

Java 9 导入导出模块

export 写自己的包路径,requires 写引入的模块名。

6. Java REPL - JShell

交互式的编程环境在其他语言如 Python 上早就有了,而 Java 上的交互式语言只到 Java 9才出现。交互式的编程可以让开发者在输入代码的时候就获取到程序的运行结果,而不用像之前一样新建文件、创建类、导包、测试一系列流程。

JShell 中支持 tab 补全代码以及自动添加分号,下面通过一个例子演示 JShell 的使用。

  1. 进入 JShell. 查看帮助文档。

    C:\Users>jshell|  欢迎使用 JShell -- 版本 9|  要大致了解该版本, 请键入: /help introjshell> /help|  键入 Java 语言表达式, 语句或声明。|  或者键入以下命令之一:|  /list [|-all|-start]|       列出您键入的源|  /edit |       编辑按名称或 id 引用的源条目|  /drop |       删除按名称或 id 引用的源条目|  /save [-all|-history|-start] |       将片段源保存到文件。|  /open |       打开文件作为源输入|  /vars [|-all|-start]|       列出已声明变量及其值|  /methods [|-all|-start]|       列出已声明方法及其签名|  /types [|-all|-start]|       列出已声明的类型|  /imports|       列出导入的项|  /exit|       退出 jshell|  /env [-class-path ] [-module-path ] [-add-modules ] ...|       查看或更改评估上下文|  /reset [-class-path ] [-module-path ] [-add-modules ]...|       重启 jshell|  /reload [-restore] [-quiet] [-class-path ] [-module-path ]...|       重置和重放相关历史记录 -- 当前历史记录或上一个历史记录 (-restore)|  /history|       您键入的内容的历史记录|  /help [|]|       获取 jshell 的相关信息|  /set editor|start|feedback|mode|prompt|truncation|format ...|       设置 jshell 配置信息|  /? [|]|       获取 jshell 的相关信息|  /!|       重新运行上一个片段|  /|       按 id 重新运行片段|  /-|       重新运行前面的第 n 个片段||  有关详细信息, 请键入 '/help', 后跟|  命令或主题的名称。|  例如 '/help /list' 或 '/help intro'。主题:||  intro|       jshell 工具的简介|  shortcuts|       片段和命令输入提示, 信息访问以及|       自动代码生成的按键说明|  context|       /env /reload 和 /reset 的评估上下文选项jshell>
  2. 定义一个变量:a = 10,遍历从 0 到 a 的数字。

    jshell> int a =10;a ==> 10jshell> for(int i=0;i0123456789
  3. 定义一个集合,赋值1,2,3,4,5。然后输出集合。

    jshell> List list = List.of(1,2,3,4,5);list ==> [1, 2, 3, 4, 5]jshell> listlist ==> [1, 2, 3, 4, 5]
  4. 查看输入过的代码。

    jshell> /list1 : int a =10;2 : for(int i=0;i   3 : List list = List.of(1,2,3,4,5);4 : list
  5. 列出导入的包。

    jshell> /imports|    import java.io.*|    import java.math.*|    import java.net.*|    import java.nio.file.*|    import java.util.*|    import java.util.concurrent.*|    import java.util.function.*|    import java.util.prefs.*|    import java.util.regex.*|    import java.util.stream.*
  6. 将代码保存到文件并退出。

    jshell> /save d:/JShell.javajshell> /exit  再见

    在 D 盘看到的保存的代码片段。

    JShell 保存的代码

操作起来还是挺简单的,还记得上面介绍集合工厂 of 方法创建出来的 setmap 数据在每个 JVM 周期里是无序的嘛?也可以用 JShell 实验下。

Set.of 的随机遍历

7. 其他更新

Java 9 中增加或者优化的功能远不止这些,上面只是列举了常用的一些新特性,更多的新特性如:

  • 不能使用下划线 _ 作为变量名,因为它是一个关键字。
  • Javadoc 支持 HTML5 并且支持搜索功能。
  • Nashorn 引擎升级,更好的支持 Javascript.
  • String 存储结构变更从 char -> byte.
  • .........

新特性很多,感兴趣的可以自己了解下。

再次预告,后续文章会结合案例图文并茂详细介绍 Java 9 开始的模块系统,感兴趣的可以关注我。此去山高水远,愿你我一路同行。

文章案例都已经上传到 Github:niumoo/jdk-feature

参考资料

  • Java Platform, Standard Edition What’s New in Oracle JDK 9

这篇文章也是 Java 新特性系列文章中的一篇,往期文章可以查看下面链接。

还看不懂同事的代码?超强的 Stream 流操作姿势还不学习一下

还看不懂同事的代码?Lambda 表达式、函数接口了解一下

Jdk14 都要出了,还不能使用 Optional优雅的处理空指针?

Jdk14 都要出了,Jdk8 的时间处理姿势还不了解一下?

还看不懂同事代码?快来补一波 Java 7 语法特性

---- END ----

与你分享我的原创文章。好看一个「在看」?

命名空间system中不存在data_Jdk14 都要出了,Jdk9 的新特性还不了解一下?相关推荐

  1. Jdk14 都要出了,Jdk9 的新特性还不了解一下?

    来源:未读代码 Java 新特性系列已经从 Java 7 开始补充到 Java 9 了,每一篇的反馈都还不错.这个系列会持续更新到 Java 13 版本,然后在每个 Java 新版本发布时同步更新这个 ...

  2. vs2022 命名空间“System”中不存在类型或命名空间名“Printing”

    在监控打印机状态的时候,需要用到System.Printing. System.Printing 命名空间 | Microsoft Learn 在微软官网有这个命名空间,其中提到 不支持命名空间中的S ...

  3. 命名空间system中不存在data_patternplot包:用ggplot解决你对线性填充,不!所有填充的全部幻想。...

    patternplot包:用ggplot解决你对线性填充,不!所有填充的全部幻想.​mp.weixin.qq.com 写在前面 patternplot包,提供了丰度的图形可视化填充选项,但是目前我尽然 ...

  4. html中写一个占内存很大死循环代码,HTML5新特性Bug:这12行代码分分钟让你浏览器崩溃iPhone重启...

    使用这十二行JavaScript代码能让firefox.chrome.safari等众多浏览器崩溃,甚至让iPhone重启? 起因 今天刷推特的时候发现Cyber Security@cyber__se ...

  5. ES6新特性_浏览器中使用ES6模块化的另一种方式--JavaScript_ECMAScript_ES6-ES11新特性工作笔记044

    然后我们再来看一下,es6的模块化在,浏览器使用的第二种方式 这里比如我有个aap.js,这个js呢,算是我们一个入口的文件 在这个里面我们可以引入 其他的js模块,比如我这个里面引入了m1.js 然 ...

  6. JDK8-JDK17中的新特性(var类型推断、模式匹配、Record、密封类)

    文章目录 1. 新语法结构 1.1 Java的REPL工具: jShell命令 1.2 异常处理之try-catch资源关闭 1.3 局部变量类型推断 1.4 instanceof的模式匹配 1.5 ...

  7. lsdyna如何设置set中的node_list_如何快速掌握es6+新特性及核心语法?

    国庆刚刚结束,我们开始一波新的学习进程吧. ECMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.作为前端必备技能,我们来快速开始吧 接 ...

  8. error CS0234: 命名空间“System.Drawing”中不存在类型或命名空间名称“Image”

    c#开发时报错: error CS0234: 命名空间"System.Drawing"中不存在类型或命名空间名称"Image" 右键项目,有个引用,添加引用,弹 ...

  9. 命名空间“System.Web”中不存在类型或命名空间名称“Optimization”解决方法

    在App_Code中添加BundleConfig.cs using System.Web.Optimization; public class BundleConfig {     public st ...

  10. 错误 CS1069 未能在命名空间“System.IO.Ports”中找到类型名

    错误 CS1069 未能在命名空间"System.IO.Ports"中找到类型名 这里写自定义目录标题 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于 ...

最新文章

  1. jenkins和docker实现自动化构建部署
  2. MassTransit_契约的创建
  3. 通过Shell开发企业级专业服务启动脚本案例(MySQL)
  4. 结构体前置申明未定义问题
  5. mysql 输出解释怎么看_了解MySQL中EXPLAIN解释命令
  6. Objective-C设计模式——单例Singleton(对象创建)
  7. [Leetcode][第410题][JAVA][分割数组的最大值][动态规划][二分]
  8. C++ 长指针与指针的区别
  9. Pentium Pro架构/流水线及其优化 (1) - 架构概述
  10. LeetCode6 Z字形变换
  11. 我的学习日志11.6
  12. 优化问题---切线、切向量、切平面;法线,法向量,法平面
  13. 服装计算机辅助设计学什么,【计算机应用论文】服装设计的计算机辅助设计应用分析(共3905字)...
  14. www.etiger.vip DEVC++练习(入门)
  15. Linux刻录光盘win10认不到,Win10不能读取DVD光驱和刻录光盘解决方法
  16. 让Android自带的Gallery实现多点缩放,拖动和边界回弹效果,效果流畅
  17. 怎么建一个新的微信群?微信小技巧
  18. python爬取微博热搜榜教程,python爬取微博热搜并存入表格
  19. Yarn Clinet模式运行spark报错问题
  20. Win8下如何安装Win7 or Win7下如何安装win8?

热门文章

  1. IGP-LAB-EIGRP-1
  2. php检查某个网站,用php开发一个检测某网站是否在正常运行的小模块
  3. unity使用屏幕后处理实现闪烁特效,创建新的shader文件过程
  4. linux 查看 java 进程内存占用情况
  5. 微信支付 ---- (微信退款,提示return_msg=证书已过期, return_code=FAIL)
  6. mysql中的sql在添加的操作中,id或者是某些字段,需要它添加自带的默认值,或者我们并不想对id或者某个字段赋值
  7. 芯烨打印机api密钥php,CCXT中文开发手册
  8. titanic数据集_数据可视化泰坦尼克号图表预测
  9. mysql从字段取出地名_mysql中从字段中URL提取域名信息
  10. 大脑计算机马云,人类和计算机谁更聪明?马云和马斯克在2019世界人工智能大会机智交锋...