jdk新特性

jdk新特性

jdk9

接口增强

JDK 8,9 两个版本中均对接口的概念做了少许拓展,现在接口支持定义默认方法,静态方法/属性,私有方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface MathUtil{
// implements 该接口的类将自动获取该方法。 - jdk 8.
default void h(){}

// 在接口定义的属性直接被视为 static。 -jdk 8.
double Pi = 3.1415;

// 可以在接口直接定义静态方法。 - jdk 8.
static void f(){}

// 可以在接口内直接定义私有方法。 -jdk 9.
private void g(){}
}

String 底层结构变更

在 JDK 8 及之前的版本当中,String 的底层使用 char[] 数组存储内容;而在 JDK 9 之后,字符串的内容实际改用 bytes[] 字节形式存储,并配合 encodingFlag 配合编码解码。这个修改对上层代码透明,即用户层面的各种 String 操作没有发生任何变化。

API:of 创建不可变序列

Map,List,Set 等现在提供 of 方法创建 不可变 的集合实例,其中 Map 支持两种创建方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<Integer> list = List.of(1, 2, 3, 4, 5);
Set<Integer> set = Set.of(1, 2, 3, 4, 5);

// k1,v1,k2,v2,...,形式创建
Map<Integer, String> map1 = Map.of(1, "v1", 2, "v2");

// 通过 Map.entry 形式创建
Map<Integer, String> map2 = Map.ofEntries(
Map.entry(1, "v1"),
Map.entry(2, "v2"),
Map.entry(3, "v3"),
Map.entry(4, "v4")
);

API:HTTP 2 协议接口

JDK 9 中引入了新的 API 以支持 HTTP 2.0 版本。注,部分 API 在 JDK 11 之后的版本发生了更替。

1
2
3
4
5
6
7
8
9
10
11
// throws IOException, InterruptedException
// 构建 client, 支持 http 2.0
HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();

// 构建请求
HttpRequest req = HttpRequest.newBuilder(URI.create("https://www.baidu.com")).build();

// 发送请求
HttpResponse<String> resp = client.send(req,HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());

jdk10

引入 var 关键字
1
2
var arrayList = new ArrayList<Integer>();

jdk11

API:字符串增强

JDK 11 新增了部分对字符串的处理方法。

1
2
3
4
5
6
println("".isBlank());      // 判断字符串是否为 "".
println(" welcome to java 17 ".strip()); // 去掉首尾空格
println(" welcome to java 17".stripLeading()); // 去掉首部空格
println("welcome to java 17 ".stripTrailing()); // 去掉尾部空格
println("word".repeat(2)); // "wordword"

lambda 表达式类型推导

JDK 11 允许将 var 关键字应用到 lambda 表达式中,起到简化声明的作用。比如:

1
2
3
4
5
6
7
8
9
10
11
@FunctionalInterface
interface Mapper<A,B>{
B map(A a);
}

// var 关键字现可以用于 lambda 表达式。
Mapper<String,Integer> string2int = (var a) -> a.length();
// 不写var也可以
Mapper<String,Integer> string2int1 = a-> a.length();


jdk13

文本块 TextBlock

JDK 13 允许使用三引号 """ 表示长文本内容。

文本块内允许插入 \ 阻止换行

另外注意,每行末尾的空格会被忽略,除非主动将其替换为 /s

1
2
3
4
5
6
7
8
9
10
11
12
var block = """
lang: java
version: 13
dbname: mysql
ip: 192.168.140.2
usr: root
pwd: 1000
""";

// 6 行
block.lines().count();

1
2
3
4
5
6
7
8
9
10
11
12
13
var block = """
lang: java\
version: 13\
dbname: mysql\
ip: 192.168.140.2\
usr: root\
pwd: 1000
""";
// 实际效果:
// "lang:javaversion: 13dbname: mysql..."
// 1 行
block.lines().count();

jdk17

密封类

在 Java 中如果想让一个类不能被继承和修改,这时我们应该使用 final 关键字对类进行修饰。不过这种要么可以继承,要么不能继承的机制不够灵活,有些时候我们可能想让某个类可以被某些类型继承,但是又不能随意继承,是做不到的。Java 15 尝试解决这个问题,引入了 sealed 类,被 sealed 修饰的类可以指定子类。这样这个类就只能被指定的类继承。

其 Sealed class 的概念和 Scala 类似,密封类不允许在包外被继承拓展,密封类必须具备子类。

具体使用:

  • 使用修饰符sealed,可以将一个类声明为密封类。密封的类使用保留关键字permits列出可以直接扩展(即extends)它的类。
  • sealed 修饰的类的机制具有传递性,它的子类必须使用指定的关键字进行修饰,且只能是 finalsealednon-sealed 三者之一。

可以在 permits 中出现的子类需要满足两个限制:

  • 如果父类在命名模块中,这些类必须在同一个模块中。
  • 如果父类在未命名模块中,这些类必须在同一个包中。

由于记录类型都是声明为 final 的。记录类型很适合作为密封类或接口的子类或实现。

java.lang.Class 中新增了两个与密封类相关的方法。isSealed() 判断 Class 对象是否表示密封类或接口。getPermittedSubclasses() 返回允许的子类的数组。

在Java类文件中,新的属性 PermittedSubclasses 用来记录允许的子类。当 JVM 定义 Java 类时,如果当前类的父类有该属性,则当前类必须出现在该属性中,否则JVM会抛出 IncompatibleClassChangeError 错误。

1
2
3
4
5
6
7
8
9
10
11
// 密封类
public sealed class People {}

// 密封类 People 必须至少有一个子类。
// 非密封的 People 子类
non-sealed class Teacher extends People{}

// 密封的 People 子类。
sealed class Driver extends People{}
non-sealed class TruckDriver extends Driver{}


参考链接:

stream_collector.md

JDK 9 - 17 新特性 / 语法概览 - 掘金 (juejin.cn)

你必须知道的Java17新特性-密封类(Sealed Classes)_Java_蜜糖的代码注释_InfoQ写作社区

详解 Java 17 中新推出的密封类 - 知乎 (zhihu.com)