【笔记】Java8以后的新特性

前言

Java8以后的新特性

交互式终端

Java9.sh
1
jshell

主方法语法糖

Java25.java
1
2
3
void main() {
...
}

注释中使用Markdown文档

Java23.java
1
2
/// # 一级标题
/// ## 二级标题

局部变量类型推断

Java10.java
1
var a = 0;

switch…case语句

switch表达式

  • case语句最后一句代码通过yield关键字定义switch语句的返回值
Java16.java
1
2
3
4
5
6
7
8
int a = 1;
int b = switch (a) {
case 1 -> {
System.out.println(a);
yield 1;
}
default -> 0;
};
  • 如果没有其他逻辑,可以省略大括号和yield关键字
Java16.java
1
2
3
4
5
int a = 1;
int b = switch (a) {
case 1 -> 1;
default -> 0;
};

switch多值匹配

  • 通过,分隔多个值
Java16.java
1
2
3
4
5
int a = 1;
int b = switch (a) {
case 1, 2 -> 1;
default -> 0;
};

switch模式匹配

  • 判断数据类型
Java21.java
1
2
3
4
5
6
Object a = 1;
int b = switch (a) {
case Integer c -> 1;
case null -> 2;
default -> 0;
};

附加条件

  • 通过when添加附加条件
Java21.java
1
2
3
4
5
6
Object a = 1;
int b = switch (a) {
case String c when c.isEmpty() -> 1;
case String c when c.isEmpty() && c.isBlank() -> 2;
default -> 0;
};

省略变量名

  • 通过_省略变量名
Java22.java
1
2
3
4
5
Object a = 1;
int b = switch (a) {
case String _ -> 1;
default -> 0;
};

自动拆装箱

自动装箱

Java23.java
1
2
3
4
int a = 1;
int b = switch (a) {
case Integer c -> 1;
};

自动拆箱

Java23.java
1
2
3
4
5
Integer a = 1;
int b = switch (a) {
case int c -> 1;
default -> 0;
};

解构

Java16.java
1
record Cls(int x) {}
Java21.java
1
2
3
4
5
Object a = 1;
int b = switch (a) {
case Cls(int x) -> x;
default -> 0;
};

嵌套匹配

Java16.java
1
record Cls(Object x) {}
Java23.java
1
2
3
4
5
int a = 1;
int b = switch (a) {
case Cls(Integer x) -> x;
default -> 0;
};

构造方法调用构造方法时,可以在this()之前编写其他代码

Java25.java
1
2
3
4
5
6
7
8
9
10
11
12
13
class Cls {
int a;
Cls(int a) {
this.a = a;
}
Cls() {

// 编写其他代码
...

this(1);
}
}

构造方法调用父类构造方法时,可以在super()之前编写其他代码

Java25.java
1
2
3
4
5
6
7
8
9
10
11
class Father {}

class Son {
Son() {

// 编写其他代码
...

super();
}
}

instanceof语法糖

Java16.java
1
2
3
4
Father son = new Son();
if (son instanceof Son son) {
System.out.println(son);
}

接口中定义私有普通方法和私有静态方法

Java9.java
1
2
3
4
5
6
7
8
interface Interface {
private void 私有普通方法名() {
...
}
private static void 私有静态方法名() {
...
}
}

记录类

定义记录类

  • 通过record关键字修饰的类是记录类,记录类名后直接通过()括号定义属性,记录类中定义的属性默认都是final
  • 记录类默认继承了java.lang.Record,所以不能再继承其他类
Java16.java
1
record 记录类名(数据类型 属性名1, 数据类型 属性名2) {}

记录类实现接口

Java16.java
1
2
3
4
5
6
7
8
9
10
interface 接口名 {
void 方法名();
}

record 记录类名(数据类型 属性名1, 数据类型 属性名2) implements 接口名 {
@Override
public void 方法名() {
...
}
}

创建对象

Java16.java
1
记录类名 变量名 = new 记录类名(值, 值);

纪录类中的默认实例方法

  • 记录类默认实现了toString()hashCode()equals()方法

获取记录对象属性值

  • 记录类默认实现了属性的Getter方法,方法名为属性名
Java16.java
1
记录变量名.属性名();

密封类

定义密封类

  • 通过sealed关键字修饰的类是密封类,密封类可以通过permits关键字指定哪些类可以继承这个密封类,多个可继承类名之间用,分隔
Java17.java
1
2
3
sealed class 密封类名 permits 可继承类名1, 可继承类名2 {
...
}

定义抽象的密封类

Java17.java
1
2
3
abstract sealed class 密封类名 permits 可继承类名1, 可继承类名2 {
...
}

定义可继承类

  • 可继承类必须通过finalsealednon-sealed关键字中的任意一个修饰,且不能同时出现

通过final修饰的类不能被继承,表示密封类最终被封死

Java17.java
1
2
3
final class 可继承类名 extends 密封类名 {
...
}

通过sealed修饰的类是密封类,表示可以继续被继承

Java17.java
1
2
3
sealed class 可继承类名 extends 密封类名 permits 其他可继承类名 {
...
}

通过non-sealed修饰的类表示非密封类,表示密封被解除了

Java17.java
1
2
3
non-sealed class 可继承类名 extends 密封类名 {
...
}

创建对象

Java17.java
1
密封类名 变量名 = new 密封类名(实参列表);

字符串实例方法

去除空白字符

  • 去除Unicode码中定义的空白字符

去除首位空白字符

Java11.java
1
String result = str.strip();

去除开头空白字符

Java11.java
1
String result = str.stripLeading();

去除结尾空白字符

Java11.java
1
String result = str.stripTrailing();

判断是否为空串

Java11.java
1
boolean result = str.isEmpty();

判断是否为空串或全部为空白字符

Java11.java
1
boolean result = str.isBlank();

字符串重复

1:重复次数

Java11.java
1
String result = str.repeat(1);

定义文本块

  • 每一行字符串起始位置由末尾的"""决定
Java15.java
1
2
String str = """
""";

Optional

执行逻辑

  • 如果不为空就执行,为空就执行其他逻辑
Java9.java
1
2
3
4
5
6
7
8
optional.ifPresentOrElse(
(obj) -> {
System.out.println("Object is not null");
},
() -> {
System.out.println("Object is null");
}
);

获取Optional对象

  • 如果当前Optional对象空就返回其他Optional对象
Java9.java
1
2
3
Optional result = optional.or(() -> {
return Optional.of(new Object());
});

获取Object对象

为空就抛异常

Java10.java
1
Object object = optional.orElseThrow();

判断是否为空

Java11.java
1
boolean result = optional.isEmpty();

映射为新的Optional对象

1
2
3
Optional result = optional.flatMap((obj) -> {
return Optional.of(new Object());
});

集合类工厂方法

  • 工厂方法最多传递10个元素作为初始元素
  • 通过工厂方法创建的集合对象都是只读的

创建List对象

Java9.java
1
List list = List.of();
Java9.java
1
List list = List.of(<value_1>, <value_2>);

创建Set对象

Java9.java
1
Set set = Set.of();
Java9.java
1
Set set = Set.of(<value_1>, <value_2>);

创建Map对象

Java9.java
1
Map map = Map.of();
Java9.java
1
Map map = Map.of(<key_1>, <value_1>, <key_2>, <value_2>);
Java9.java
1
Map map = Map.ofEntries(Map.entry(<key_1>, <value_1>), Map.entry(<key_2>, <value_2>));

有序集合的语义化方法

添加元素

头部添加元素

Java21.java
1
list.addFirst(<value>);

尾部添加元素

Java21.java
1
list.addLast(<value>);

删除元素

头部删除元素

Java21.java
1
list.removeFirst();

尾部删除元素

Java21.java
1
list.removeLast();

获取元素

头部获取元素

Java21.java
1
Object item = list.getFirst();

尾部获取元素

Java21.java
1
Object item = list.getLast();

反向视图

Java21.java
1
List result = list.reversed();

Stream

获取Stream对象

通过工厂方法创建Stream对象

  • 定义不包含null,并且可以有多个元素的Stream对象
Java9.java
1
Stream stream = Stream.of(<value_1>, <value_2>);
  • 定义可以包含null,并且只有一个元素的Stream对象
Java9.java
1
Stream stream = Stream.ofNullable(<value>);

通过String对象获取Stream对象

  • 根据换行符作为分隔符得到Stream中的每个元素
1
2
3
String str = new String();

Stream<Object> stream = str.lines();

流式处理数据

过滤

  • Lambda表达式返回true的数据会被保留,返回false立即终止之后的遍历
Java9.java
1
2
3
stream = stream.takeWhile((item) -> {
return true;
});
  • Lambda表达式返回true的数据会被丢弃,返回false立即终止之后的遍历
Java9.java
1
2
3
stream = stream.dropWhile((item) -> {
return true;
});

收尾操作

将Stream中的所有元素转换为List集合

Java16.java
1
List<Object> list = stream.toList();

I/O流

文件字节流

输入流

读取全部字节
Java9.java
1
fileInputStream.readAllBytes();
读取指定长度的字节

0:开始读取位置偏移量
<length>:读取的长度

Java9.java
1
2
byte[] bytes = new byte[<length>];
fileInputStream.readNBytes(bytes, 0, <length>);
Java11.java
1
fileInputStream.readNBytes(<length>);
跳过指定长度的字节

<length>:跳过的长度

Java11.java
1
fileInputStream.skipNBytes(<length>);
获取空输出流
  • 向空输出流写入的数据会被丢弃
Java11.java
1
InputStream stream = InputStream.nullInputStream();

输入流直接传输到输出流

Java9.java
1
2
3
4
5
try (FileInputStream fileInputStream = new FileInputStream("<file>"); FileOutputStream fileOutputStream = new FileOutputStream("<file>")) {
fileInputStream.transferTo(fileOutputStream);
} catch (IOException e) {
e.printStackTrace();
}

多线程

通过线程生成器创建线程对象

创建平台线程对象

name():定义线程名
priority():定义优先级
daemon():定义是否为守护线程

false:缺省值,不是守护线程
true:是守护线程

inheritInheritableThreadLocals():定义子线程InherableThreadLocal对象是否可以继承父线程的InherableThreadLocal对象设置的数据

true:缺省值,可以继承
false:不可以继承

uncaughtExceptionHandler():定义未捕获异常处理器
start():创建线程对象并启动

Java21.java
1
2
3
4
5
6
7
8
9
10
11
Thread.ofPlatform()
.name("")
.priority(0)
.daemon(false)
.inheritInheritableThreadLocals(true)
.uncaughtExceptionHandler((t, e) -> {
...;
})
.start(() -> {
...
});

unstarted():创建线程对象并返回

Java21.java
1
2
3
4
5
6
7
8
9
10
11
Thread thread = Thread.ofPlatform()
.name("")
.priority(0)
.daemon(true)
.inheritInheritableThreadLocals(false)
.uncaughtExceptionHandler((t, e) -> {
...;
})
.unstarted(() -> {
...
});

虚拟线程

  • 虚拟线程默认都是守护线程,且不可改为非守护线程

创建虚拟线程

Java21.java
1
2
3
Thread.startVirtualThread(() -> {
...
});

反射

获取类对象

基本类型获取类对象

Java22.java
1
Class<?> clazz = Class.forPrimitive("int");

完成

参考文献

哔哩哔哩——青空の霞光