一、前言
本文标题虽然名为Java11新特性,但实际上包含了Java9、Java10的新特性,并且只讨论Java语言层面,不涉及JDK相关内容。
因为Java8与Java11为LTS版本,通常情况下应用直接从Java8升级到Java11,所以将Java9、Java10的新特性一并归入Java11中进行讨论。
如果应用基于Java9或Java10,请务必自行确认版本新特性。
二、实用的新特性
接口支持私有方法
public interface AInterface {
default void process1(int val) {
log(val);
}
default void process2(int val) {
log(val);
}
// default接口可以使用该private方法,使得接口中的代码也能复用
private void log(int val) {
System.out.printf("process[%d]%n", val);
}
}
Stream新增ofNullable静态方法
List<String> strings = getList();
// JDK8中实现避免strings为null
List<String> jdk8 = Optional.ofNullable(strings).orElseGet(ArrayList::new)
.stream()
.peek(val -> {
// do something
})
.collect(Collectors.toList());
// JDK11中实现避免strings为null
List<String> jdk11 = Stream.ofNullable(strings)
.flatMap(Collection::stream)
.peek(val -> {
// do something
})
.collect(Collectors.toList());
集合新增of工厂方法
// 生成不可变的空List
List<String> emptyList = List.of();
// 生成[1, 2, 3]的不可变List
List<Integer> integers = List.of(1, 2, 3);
// 生成[a, b, c]的不可变Set
Set<String> stringSet = Set.of("a", "b", "c");
// 生成{key1: val1, key2: val2}的不可变Map
Map<String, String> map = Map.of("key1", "val1", "key2", "val2");
这些工厂方法有一些有意思之处,以List.of()源码举例,该方法有多个重载,入参从0到10个,同时支持可变参数:
static <E> List<E> of() {
return ImmutableCollections.emptyList();
}
static <E> List<E> of(E e1) {
return new ImmutableCollections.List12<>(e1);
}
static <E> List<E> of(E e1, E e2) {
return new ImmutableCollections.List12<>(e1, e2);
}
// ...
// ...
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
e6, e7, e8, e9, e10);
}
@SafeVarargs
@SuppressWarnings("varargs")
static <E> List<E> of(E... elements) {
switch (elements.length) { // implicit null check of elements
case 0:
return ImmutableCollections.emptyList();
case 1:
return new ImmutableCollections.List12<>(elements[0]);
case 2:
return new ImmutableCollections.List12<>(elements[0], elements[1]);
default:
return new ImmutableCollections.ListN<>(elements);
}
}
个人推测这么设计的原因是Java中的可变参数本质上是数组,而开发者通常不会传入太多的对象来使用of方法构造集合,所以枚举出常见入参数量的方法,可以避免数组在内存中申请连续空间并降低垃圾回收上的开销。
try-with-resources增强
// JDK8中使用try-with-resources必须在try块中声明并赋值变量
try (FileInputStream fileInputStream = new FileInputStream("test.txt")) {
int val;
while ((val = fileInputStream.read()) != -1) {
System.out.println(val);
}
} catch (IOException e) {
e.printStackTrace();
}
// JDK11中try-with-resources可以直接使用代码上文中的变量
FileInputStream fileInputStream = new FileInputStream("test.txt");
try (fileInputStream) {
int val;
while ((val = fileInputStream.read()) != -1) {
System.out.println(val);
}
} catch (IOException e) {
e.printStackTrace();
}
变量类型标识符var(只能用于局部变量)
// 创建int
var intValue = 1;
intValue += 1; // intValue = 2
// 创建一个int数组
var numbers = new int[] {1, 2, 3};
System.out.println(numbers.length); // length = 3
// 创建一个String列表
var strings = new ArrayList<String>();
strings.add("a");
strings.add("b");
System.out.println(strings.size()); // size = 2
// 通过方法的返回值自动推断类型
var flag = foo();
if (flag) {
System.out.println(flag); // true
}
// 利用面向接口编程简化三元表达式
var collection = isFoo() ? List.of(1, 2, 3) : Set.of(4, 5, 6);
collection.stream().peek(i -> i += 1).collect(Collectors.toList());
// 甚至能这么写三元表达式
var anyData = isFoo() ? 123 : "123";
// 简化增强for循环中的声明,无需在IDEA自动提示中寻找对应的类名,lambda中的入参同理
List<Pojo> pojoList = List.of(new Pojo(), new Pojo());
for (var pojo : pojoList) {
System.out.println(pojo);
}
String新增若干方法
// true
" ".isBlank();
// strip()和trim()区别在于 trim()仅仅删除字符<=U+0020的空格,strip()能删除所有unicode格式空格
" Java11 ".strip(); // "Java11"
// "Java11 "
" Java11 ".stripLeading();
// " Java11"
" Java11 ".stripTrailing();