Java 语法糖

Java 语法糖

[TOC]

Java8

https://www.runoob.com/java/java8-new-features.html

Java9

https://www.runoob.com/java/java9-new-features.html

改进的 try-with-resources

try-with-resources 是 JDK 7 中一个新的异常处理机制,它能够很容易地关闭在 try-catch 语句块中使用的资源。所谓的资源(resource)是指在程序完成后,必须关闭的对象。try-with-resources 语句确保了每个资源在语句结束时关闭。所有实现了 java.lang.AutoCloseable 接口(其中,它包括实现了 java.io.Closeable 的所有对象),可以使用作为资源。

try-with-resources 声明在 JDK 9 已得到改进。如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。

1
2
3
4
5
6
7
8
9
BufferedReader br = new BufferedReader(inputString);
try (BufferedReader br1 = br) {
return br1.readLine();
}

BufferedReader br = new BufferedReader(inputString);
try (br) {
return br.readLine();
}

Java10

var 局部变量类型推断(JEP 286)

1
2
3
4
5
6
7
8
9
var numbers = List.of(1, 2, 3, 4, 5); // inferred value ArrayList<String>
// Index of Enhanced For Loop
for (var number : numbers) {
System.out.println(number);
}
// Local variable declared in a loop
for (var i = 0; i < numbers.size(); i++) {
System.out.println(numbers.get(i));
}

Java14

instanceof 模式匹配

1
2
3
4
5
6
void demo(Object obj) {
if (obj instanceof String) { // comparison
String s = (String) obj; // New variable & explicit casting
System.out.println(s.toUpperCase()); // access member
}
}

简写后

1
2
3
4
5
6
7
8
9
10
11
12
13
void demo(Object obj) {
if (obj instanceof String s) { // comparison
System.out.println(s.toUpperCase()); // access member
}
}

@Override
public boolean equals(Object obj){
return (obj instanceof Keyboard other &&
model.equals(other.model) &&
price == other.price);
}
}

Records

我们先来看看现在我们如何声明一个数据类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Range {

private final int min;
private final int max;

public Range(int min, int max) {
this.min = min;
this.max = max;
}

public int getMin() {
return min;
}

public int getMax() {
return max;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Range range = (Range) o;
return min == range.min && max == range.max;
}

@Override
public int hashCode() {
return Objects.hash(min, max);
}

@Override
public String toString() {
return "Range{" +
"min=" + min +
", max=" + max +
'}';
}
}

我们来看看这个类的特点:

  • 没有无参构造方法,需要初始化时对成员变量赋值
  • 成员变量只有 getter 方法。
  • 覆写了 超类 ObjectequalshashCodetoString 方法。

虽然我们可以借助于第三方框架或者 IDE 很容易编写这些样板代码,但是总归要写这些样板代码不是吗?

上面的冗长的代码在 Java 14 中我们可以这么写:

1
public record Range(int min, int max) {}

没错就是这个简单!这个语法糖是不是有 “卧槽” 的感觉?我们声明这种类使用 record 标识(目前不知道 record 会不会上升到关键字的高度)。当你用 record 声明一个类时,该类将自动拥有以下功能:

  • 获取成员变量的简单方法,以上面代码为例 min()max() 。注意区别于我们平常getter的写法。
  • 一个 equals 方法的实现,执行比较时会比较该类的所有成员属性
  • 重写 equals 当然要重写 hashCode
  • 一个可以打印该类所有成员属性的 toString 方法。
  • 请注意只会有一个构造方法。

因为这个特性是 preview feature,默认情况下是无法编译和执行的。同样以上面为例我们需要执行:

1
2
$ javac -d classes --enable-preview --release 14 Range.java
$ java -classpath classes --enable-preview Range

Jshell 中运行

1
2
3
4
5
6
7
8
9
10
11
jshell> Range r = new Range(10, 20);
r ==> Range[min=10, max=20]

jshell> r.min()
$5 ==> 10

jshell> r.toString()
$6 ==> "Range[min=10, max=20]"

jshell> r
r ==> Range[min=10, max=20]

虽然 record 声明的类没有 final 关键字,实际上它是一个不可变类。除了一些限制外,它依旧是一个普通的Java 类。因此,我们可以像添加普通类一样添加逻辑。我们可以在构造实例时强制执行前提条件:

1
2
3
4
5
6
public record Range(int min, int max) {
public Range {
if (min >= max)
throw new IllegalArgumentException("min should be less than max");
}
}

另外我们也可以给 Records 类增加普通方法、静态属性、静态方法,这里不再举例;

为了简化语法糖的推理,不能在类内声明成员属性。以下是错误的示范:

1
2
3
4
public record Range(int min, int max) {
// 错误的示范
private String name;
}