一、JDK9新特性

发布:admin2025-12-16 03:16:50 5254条浏览分类:跨服战场

一、JDK9新特性

1. 概述

JDK9新特性主要包括:

模块化系统

JShell

只读集合工厂方法

接口的私有方法

String存储结构改变

try...catch升级

平台日志API和服务

垃圾回收器

2. 模块化系统

没有使用模块化时存在的问题:

导入依赖时,需要加载全部的包,影响系统性能。

Java 运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存加载,主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程序运行需要的class)

当代码库越来越大,创建复杂,盘根错节的“意大利面条式代码”的几率呈指数级的增长。不同版本的类库交叉依赖导致让人头疼的问题,这些都阻碍了 Java 开发和运行效率的提升。

很难真正地对代码进行封装, 而系统并没有对不同部分(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到,这样就会导致无意中使用了并不想被公开访问的 API。

本质上讲也就是说,用模块来管理各个package,通过声明某个package暴露,模块(module)的概念,其实就是package外再裹一层,不声明默认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。

使用模块化系统,可以按需导入对应的模块。

实现目标

模块化的主要目的在于减少内存的开销

只须必要模块,而非全部jdk模块,可简化各种类库和大型应用的开发和维护

改进 Java SE 平台,使其可以适应不同大小的计算设备

改进其安全性,可维护性,提高性能

使用

在src下创建module-info.java

导出:

module xxx{

exports 包名/模块;

}

导入:

module xxx{

requires 包名/模块;

}

3. JShell命令

像Python 和 Scala 之类的语言早就有交互式编程环境 REPL (read - evaluate - print - loop)了,以交互式的方式对语句和表达式进行求值。开发者只需要输入一些代码,就可以在编译前获得对程序的反馈。而之前的Java版本要想执行代码,必须创建文件、声明类、提供测试方法方可实现。

4. 接口的私有方法

public interface JDK9Demo4 {

//接口默认都是共有静态常量

public static final int NUM = 10;

//接口默认方法都是抽象方法

public abstract void method1();

//jdk8接口可以有静态方法

public static void method2(){

System.out.println("接口中的静态方法");

}

//jdk8接口可以有默认方法

public default void method3(){

System.out.println("接口中的默认方法");

}

//jdk9接口可以有私有方法

private void method4(){

System.out.println("接口中的私有方法");

}

}

5. 钻石操作符升级

Comparator com = new Comparator<>() {

@Override

public int compare(Object o1, Object o2) {

return 0;

}

};

在jdk8中 上面的代码会报错:<>必须写明类型,jdk9对<>做了升级,不写也不报错。

6. try...catch

在jdk8中,可以自动关闭资源,但必须在try子句中初始化。

jdk9可以在外部初始化,try子句写对象名,也可以自动关闭。

try(inputStream;outputStream){

}

7. String存储结构变更

不再使用char[]存储,改为byte[],节省空间。

同样的,StringBuffer 和 StringBuilder也做了存储结构的变更。

8. of() 创建只读集合

jdk9引入了of()方法,可以方便的创建只读集合

public class Demo5 {

public static final List list = List.of("type_weixin","type_zhifubao","type_yinhangka");

public static void main(String[] args) {

//jdk8以前创建只读集合

List list = new ArrayList<>();

list.add("张三");

list.add("李四");

list.add("王五");

Collection list2 = Collections.unmodifiableCollection(list);

// list2.add("赵六");

// System.out.println(list2);

//jdk9创建只读集合

List list3 = List.of("张三", "李四", "王五");

System.out.println(list3);

Set set1 = Set.of("AA", "BB", "CC");

System.out.println(set1);

Map map = Map.of("k1", "v1", "k2", "v2");

System.out.println(map);

}

}

9. InputStream增强

使用 transferTo 可以将输入流中的内容直接交给输出流输出

10. stream API增强

在 Java 9 中,Stream API 变得更好,Stream 接口中添加了 4 个新的方法:takeWhile, dropWhile, ofNullable,还有个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。

除了对 Stream 本身的扩展,Optional 和 Stream 之间的结合也得到了改进。现在可以通过 Optional 的新方法 stream() 将一个 Optional 对象转换为一个(可能是空的) Stream 对象。

10.1 takeWhile()

用于从 Stream 中获取一部分数据,接收一个 Predicate 来进行选择。在有序的Stream 中,takeWhile 返回从开头开始的尽量多的元素。

public static void main(String[] args) throws Exception {

List list = Arrays.asList(10,20,30,40,30,20,10);

list.stream().takeWhile(t->t<40).forEach(System.out::println);

List list2 = Arrays.asList(1,2,3,4,5,6,7);

list2.stream().takeWhile(t->t<7).forEach(System.out::println);

}

10.2 dropWhile()

dropWhile 的行为与 takeWhile 相反,返回剩余的元素。

10.3 ofNullable()

Java 8 中 Stream 不能完全为null,否则会报空指针异常。

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

public static void main(String[] args) throws Exception {

//允许通过

Stream streams = Stream.of("AA","BB",null);

System.out.println(streams.count());

//不允许通过

/*Stream stream2 = Stream.of(null);

System.out.println(stream2.count());*/

//允许通过

Stream stream2 = Stream.ofNullable(null);

System.out.println(stream2.count());

}

10.4 iterate() 重载

这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。

public static void main(String[] args) throws Exception {

//原始方式

Stream.iterate(1,i->i+1).limit(50).forEach(System.out::println);

//增强方式

Stream.iterate(1,i->i<60,i->i+1).forEach(System.out::println);

}

10.5 Optional类中stream()使用

public static void main(String[] args) throws Exception {

List list = new ArrayList<>();

list.add("张三");

list.add("李四");

list.add("王五");

list.add("赵六");

Optional> optional = Optional.ofNullable(list);

optional.stream().flatMap(x->x.stream()).limit(2).forEach(System.out::println);

list.stream().limit(2).forEach(System.out::println);

}

Optional接收一个集合对象,底层也是用集合容器进行存储,所以使用一次流进行遍历得到的是集合对象,

调用flatMap方法 能获取到集合中的元素

二、JDK10新特性

1. 局部变量类型推断

使用var声明变量,var进行类型推断

public class Demo1 {

public static void main(String[] args) {

method1();

}

public static void method1(){

var i = 1;

var list = new ArrayList();

list.add("张三");

list.add("李四");

System.out.println(list);

}

}

var不是一个关键字。

var没有改变java是强语言的本质,只是进行类型的推断。

以下情况不能推断:

public static void method2(){

//由于值是null,类型无法推断

// var i = null;

//方法引用无法使用var

//var a = System.out::println;

//lamdba无法推断var的类型,故不能用

/* Function fun = (Integer a)->{

return a+"";

};*/

/* var fun2 = (Integer a)->{

return a+"";

};*/

//静态数组后面不加类型的时候推断不出来var的类型,故不能用

int[] arr = new int[]{1,2,3};

int[] arr2 = {1,2,3};

//var arr3 = {1,3,4};

}

2. 新增只读集合方法 copyOf()

public static void main(String[] args) throws Exception {

//示例1

var list1 = List.of("AA","BB","CC");

var list2 = List.copyOf(list1);

System.out.println(list1==list2);//true

//示例2

var list3 = new ArrayList();

list3.add("AA");

list3.add("BB");

List list4 = List.copyOf(list3);

System.out.println(list3==list4); //false

}

copyOf 方 法 会 先 判 断 来 源 集 合 是 不 是AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创建一个新的集合。

示例2因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类,所以 copyOf 方法又创建了一个新的实例,所以为false。

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

三、JDK11新特性

1. ZGC垃圾回收器

GC是java主要优势之一。 然而, 当GC停顿太长, 就会开始影响应用的响应时间。消除或者减少GC停顿时长, java将对更广泛的应用场景是一个更有吸引力的平台。此外, 现代系统中可用内存不断增长,用户和程序员希望JVM能够以高效的方式充分利用这些内存, 并且无需长时间的GC暂停时间。

ZGC, A Scalable Low-Latency Garbage Collector(Experimental)ZGC, 这应该是JDK11最为瞩目的特性, 没有之一。 但是后面带了Experimental,说明这还不建议用到生产环境。

ZGC是一个并发, 基于region, 压缩型的垃圾收集器, 只有root扫描阶段会STW(stop the world), 因此GC停顿时间不会随着堆的增长和存活对象的增长而变长。

优势:

GC暂停时间不会超过10ms

既能处理几百兆的小堆, 也能处理几个T的大堆(OMG)

和G1相比, 应用吞吐能力不会下降超过15%

为未来的GC功能和利用colord指针以及Load barriers优化奠定基础

初始只支持64位系统

2. Optional加强

3. 新增HTTP客户端API

HTTP,用于传输网页的协议,早在1997年就被采用在目前的1.1版本中。直到2015年,HTTP2才成为标准。

HTTP/1.1和HTTP/2的主要区别是如何在客户端和服务器之间构建和传输数据。HTTP/1.1依赖于请求/响应周期。 HTTP/2允许服务器“push”数据:它可以发送比客户端请求更多的数据。这使得它可以优先处理并发送对于首先加载网页至关重要的数据。

这是 Java 9 开始引入的一个处理 HTTP 请求的的 HTTP Client API,该API 支持同步和异步,而在 Java 11 中已经为正式可用状态,你可以在java.net 包中找到这个 API。

它 将 替 代 仅 适 用 于 blocking 模 式 的 HttpURLConnection(HttpURLConnection是在HTTP 1.0的时代创建的,并使用了协议无关的方法),并提供对WebSocket 和 HTTP/2的支持

public static void main(String[] args) throws Exception {

HttpClient client = HttpClient.newHttpClient();

HttpRequest request =

HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build();

HttpResponse.BodyHandler responseBodyHandler = HttpResponse.BodyHandlers.ofString();

HttpResponse response = client.send(request, responseBodyHandler);

String body = response.body();

System.out.println(body);

}

四、JDK14新特性

在NullPointerException时,指明为null的变量

之前:

jdk14:

五、JDK15新特性

新增 text blocks 文本块,解决多行字符串换行问题

public static void main(String[] args) {

//jdk15增加文本块

String str = """

hello

world

hahaha

""";

}

六、JDK16新特性

在Java16中正式发布Switch升级,其目的是为了解决switch语句的一些不规则性成为障碍

比如case标签之间的默认控制行为

case块中的默认范围

无意义的break语句。

public static void main(String[] args) {

int level = new Random().nextInt(4);

String strLevel;

switch (level){

case 1 -> strLevel="优秀";

case 2 -> strLevel="良好";

default -> strLevel="一般";

}

System.out.println(strLevel);

}

还可以写成:

public static void main(String[] args) {

int level = new Random().nextInt(4);

String strLevel = switch (level){

case 1-> "优秀";

case 2-> "良好";

default -> "一般";

};

System.out.println(strLevel);

}

根据月份判断季节:

public static void main(String[] args) {

int level = new Random().nextInt(12);

String jiJi = null;

switch (level){

case 3,4,5 -> jiJi = "春天";

case 6,7,8 -> jiJi = "夏天";

case 9,10,11 -> jiJi = "秋天";

case 12,1,2 -> jiJi = "冬天";

};

System.out.println(jiJi);

}

还有:

public static void main(String[] args) {

int level = new Random().nextInt(4);

String strLeave = switch (level){

case 1 -> {

System.out.println("优秀");

yield "优秀";

}

default -> "进步空间很大";

};

System.out.println(strLeave);

}

虽然写法更简单了,但是编译后的代码还是原本的格式,只是做了翻译。