更多Java内容查看:https://dullfan.notion.site/Java-71a7344dba09438c8851b8514a9b5df3
目录
可以自行查看官方以及wiki
Java SE | Oracle Technology Network | Oraclehttps://www.oracle.com/java/technologies/java-se-glance.htmlhttps://zh.wikipedia.org/wiki/Java%E7%89%88%E6%9C%AC%E6%AD%B7%E5%8F%B2#Java_SE_23
https://zh.wikipedia.org/wiki/Java%E7%89%88%E6%9C%AC%E6%AD%B7%E5%8F%B2#Java_SE_23
Java8
Lambda表达式
主要用于简化匿名类的写法
Runnable runnable = () -> System.out.println("我是一个Lambda");
runnable.run();
函数式接口
函数式接口是只有一个抽象方法的接口
@Test
void contextLoads() {
StringSplice splice = (a,b)-> a + b;
System.out.println(splice.splice("函数式","接口"));
}
// 表明该接口被设计用于支持 Lambda 表达式和函数式编程。这为其他开发人员阅读和理解代码提供了明确的提示
// Java 编译器会对被标记为@FunctionalInterface的接口进行检查,确保该接口只有一个抽象方法(除了从Object类继承的方法之外)。如果违反了这个规则,编译器会报错。
@FunctionalInterface
interface StringSplice{
String splice(String a,String b);
}
Stream API
提供了高效的数据处理方式,支持对集合进行过滤、排序等操作
List<String> names = Arrays.asList("张三", "李四", "王五");
// 过滤以 '张' 开头的名字并排序
names.stream()
.filter(name -> name.startsWith("张"))
.sorted()
.forEach(System.out::println);
详细:https://dullfan.notion.site/Stream-46cdab65e6cb46b0b5a21caae34d535a
默认方法和静态方法
@Test
void contextLoads() {
Interface.staticMethod();
new MyClass().defaultMethod();
}
interface Interface{
// default 只能使用在接口中
// 作用:只要在一个接口中添加了默认方法,所有的实现类就会自动继承,不需要改动任何代码,选择性覆盖
default void defaultMethod(){
System.out.println("默认方法执行");
}
// 不能被重写
static void staticMethod(){
System.out.println("静态方法执行");
}
}
static class MyClass implements Interface{
// 选择性覆盖默认方法,
}
方法引用
是对Lambda一种简化写法,可以直接引用现有的方法或构造函数
List<String> names = Arrays.asList("张三", "李四", "王五");
// 使用方法引用替代 Lambda 表达式
names.forEach(System.out::println);
Optional
表示该值可能为空,为了防止空指针异常
Optional<String> optional = Optional.ofNullable("Optional");
optional.ifPresent(System.out::println);
// 如果值为空,返回默认值
String result = optional.orElse("默认值");
System.out.println(result);
新日期和时间
提供了更好的日期和时间处理功能
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
// 格式化日期时间
DateTimeFormatter formatterDate = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter formatterTime = DateTimeFormatter.ofPattern("HH:mm:ss");
DateTimeFormatter formatterDateTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDate= date.format(formatterDate);
String formattedTime = time.format(formatterTime);
String formattedDateTime = dateTime.format(formatterDateTime);
System.out.println(formattedDate); // 输出当前日期
System.out.println(formattedTime); // 输出当前时间
System.out.println(formattedDateTime); // 输出格式化后的日期时间
详细:https://dullfan.notion.site/LocalDate-ad0c2470ff34447dac9e58d36575902d
Base64
引入了Base64类,用于处理Base64编码和解码操作
String originalInput = "Hello, Base64!";
// Base64 是一种编码方式,主要用于将二进制数据编码成 ASCII 字符集的可打印字符,以便在不同的系统和协议中进行传输和存储。
String encodedString = Base64.getEncoder().encodeToString(originalInput.getBytes());
System.out.println(encodedString); // 输出编码后的字符串
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
String decodedString = new String(decodedBytes);
System.out.println(decodedString); // 输出 Hello, Base64!
重复注解
允许在同一个位置多次使用相同的注解
@Test
void contextLoads() {
try {
// 通过反射获取注解中的参数
Method method = MyClass.class.getMethod("myMethod");
MyAnnotation[] annotations = method.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation annotation : annotations) {
System.out.println("Annotation value: " + annotation.value());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Repeatable(MyAnnotations.class)
@interface MyAnnotation {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@interface MyAnnotations {
MyAnnotation[] value();
}
public class MyClass {
@MyAnnotation("First method annotation")
@MyAnnotation("Second method annotation")
public void myMethod() {
// 方法实现
}
}
详细:https://dullfan.notion.site/2b21f66c2a814477b156771958f79957
Java9
改进的集合工厂方法
为 List
、Set
和 Map
引入了方便的工厂方法,使用这些方法可以轻松地创建不可变的集合。
List<String> list = List.of("A", "B", "C");
Set<String> set = Set.of("A", "B", "C");
Map<Integer, String> map = Map.of(1, "A", 2, "B", 3, "C");
System.out.println(list); // 输出 [A, B, C]
System.out.println(set); // 输出 [A, B, C]
System.out.println(map); // 输出 {1=A, 2=B, 3=C}
接口私有化
允许在接口中定义私有方法。
@Test
void contextLoads() {
MyInterface myClass = new MyClass();
myClass.publicMethod();
}
interface MyInterface {
default void publicMethod() {
System.out.println("Public Method");
privateMethod();
}
private void privateMethod() {
System.out.println("Private Method");
}
}
class MyClass implements MyInterface {}
HTTP
引入了一个新的 HTTP/2 客户端 API(在 java.net.http
包中),它可以处理同步和异步的 HTTP 请求。这是一个实验性特性,在 Java 11 中被正式引入
@Test
void contextLoads() throws URISyntaxException, IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("<https://postman-echo.com/get>"))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
Java10
var
var
关键字,用于局部变量类型推断,这意味着在声明局部变量时,编译器可以根据赋值的表达式自动推断变量的类型
var number = 10; // 自动推断为 int 类型
var text = "Hello, Java 10"; // 自动推断为 String 类型
var list = List.of(1, 2, 3, 4); // 自动推断为 List<Integer> 类型
System.out.println(number); // 输出 10
System.out.println(text); // 输出 Hello, Java 10
System.out.println(list); // 输出 [1, 2, 3, 4]
注意:
var
只能用于局部变量,包括循环变量、for-each
循环中的变量、以及局部变量的初始化var
不能用于类级别的字段声明,也不能用于方法参数或返回类型
Java11
var 扩展 Lambda
允许在 lambda 表达式的参数中使用 var
关键字
var list = List.of("Apple", "Banana", "Orange");
list.forEach((var item) -> System.out.println(item)); // 使用 var 关键字
// 可以为 lambda 参数添加注解
Consumer<String> consumer = (var item) -> System.out.println(item);
list.forEach(consumer);
String 新方法
为 String
类增加了一些非常实用的新方法,比如 isBlank()
、lines()
、strip()
、repeat()
和 stripLeading()
等
// isBlank()
System.out.println(" ".isBlank()); // 输出 true
// lines()
String multilineStr = "Java\\nis\\nawesome";
multilineStr.lines().forEach(System.out::println); // 输出三行
// strip(), stripLeading(), stripTrailing()
String str = " hello ";
System.out.println(">" + str.strip() + "<"); // 输出 >hello<
System.out.println(">" + str.stripLeading() + "<"); // 输出 >hello <
System.out.println(">" + str.stripTrailing() + "<"); // 输出 > hello<
// repeat()
String repeatStr = "Hello ";
System.out.println(repeatStr.repeat(3)); // 输出 Hello Hello Hello
Java12
Switch表达式
Switch 表达式作为预览功能。这使得 switch
语句可以作为一个表达式来使用,从而返回值并减少样板代码
int day = 3;
String dayName = switch (day){
case 1 -> "星期一";
case 2 -> "星期二";
case 3 -> "星期三";
case 4 -> "星期四";
case 5 -> "星期五";
case 6 -> "星期六";
case 7 -> "星期七";
default -> "未知";
};
System.out.println(dayName);
Java13
Switch表达式改进
可以使用yield
返回值
int day = 3;
String dayName = switch (day){
case 1 -> "星期一";
case 2 -> "星期二";
case 3 -> "星期三";
case 4 -> "星期四";
case 5 -> "星期五";
case 6 -> "星期六";
case 7 -> "星期七";
default -> {
String result = "数据处理: " + day;
yield result;
}
// default -> throw new IllegalArgumentException("错误: " + day);
};
System.out.println(dayName);
文本块
文本块(Text Blocks)是一个用于处理多行字符串的预览特性。它允许开发者编写多行字符串而无需使用繁琐的转义字符,并保留格式。
String json = """
{
"name":"DullFan",
"age":20
}
""";
System.out.println(json);
说明:
- 文本块使用
"""
作为分隔符。 - 文本块保留了字符串的格式和缩进,使得代码更具可读性。
Java14
Record Classes
用于简化不可变数据类的定义,记录类自动生成构造函数等方法,该类中字段使用的是final
Point point = new Point(1, 2);
System.out.println(point); // 输出 Point[x=1, y=2]
System.out.println(point.x); // 1
System.out.println(point.y); // 2
instanceof 匹配
减少了类型转换的样板代码
Object obj = "Hello!";
if (obj instanceof String s) {
System.out.println(s.toUpperCase());
}
Java15
密封类
允许开发者控制哪些类可以继承或实现它。这为构建受控层次结构提供了更多的灵活性和安全性
sealed class Shape permits Circle,Square{}
final class Circle extends Shape{}
final class Square extends Shape{}
说明:
sealed
关键字定义了一个密封类,后面跟随permits
关键字,指定允许扩展该类的子类。- 其他类如果没有被允许,将不能继承或实现密封类
Java16
JDK 16 发布于 2021 年 3 月 16 日。Java 16 移除了 AOT 编译及 Graal JIT 的选项。自 Java 16 开始,允许使用 C++14 来编写 Java 的实现(但仍不允许 C++17、C++20 等版本),且代码迁移到了 GitHub,不再使用 Mercurial 版本控制系统。
- JEP 338:Vector API(孵化)
- JEP 347:启用 C++14 语言特性
- JEP 357:从 Mercurial 迁移到 Git
- JEP 369:迁移到 GitHub
- JEP 376:ZGC: 并发的线程栈处理
- JEP 380:用于 Unix 域套接字的 Channel
- JEP 386:Alpine Linux 的移植版本
- JEP 387:可伸缩的 Metaspace
- JEP 388:Windows/AArch64 的移植版本
- JEP 389:外部链接器 API(孵化)
- JEP 390:对值类型的类(Value-based Classes)发出警告
- JEP 392:打包工具
- JEP 393:外部内存访问 API(第三孵化版本)
- JEP 394:使用 instanceof 的模式匹配
- JEP 395:记录类
- JEP 396:在缺省情况下对 JDK 内部进行强封装
- JEP 397:密封类(第二预览版本)
Java17
伪随机数生成器
伪随机数生成器 (pseudorandom number generator,PRNG,又称为确定性随机位生成器)增加了新的接口类型和实现,使得开发者更容易在应用程序中互换使用各种 PRNG 算法。
RandomGeneratorFactory<RandomGenerator> l128X256MixRandom = RandomGeneratorFactory.of("L128X256MixRandom");
// 使用时间戳作为随机数种子
RandomGenerator randomGenerator = l128X256MixRandom.create(System.currentTimeMillis());
// 生成随机数
int i = randomGenerator.nextInt(100);
System.out.println(i);
switch类型匹配
static void testFooBar(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
static String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
Java18
JDK 18 发布于 2022 年 3 月 22 日。
- JEP 400:默认使用 UTF-8
- JEP 408:简易 Web 服务器
- JEP 413:Java API 文档中的代码片段
- JEP 416:使用 Method Handle 重新实现核心反射
- JEP 417:Vector API(第三孵化版本)
- JEP 418:因特网地址解析 SPI
- JEP 419:外部函数与内存 API(第二预览版本)
- JEP 420:使用 switch 的模式匹配(第二预览版本)
- JEP 421:弃用 Finalization 以待后续移除
Java19
虚拟线程
虚拟线程(Virtual Thread)是 JDK 而不是 OS 实现的轻量级线程(Lightweight Process,LWP),由 JVM 调度。许多虚拟线程共享同一个操作系统线程,虚拟线程的数量可以远大于操作系统线程的数量。
在引入虚拟线程之前,java.lang.Thread
包已经支持所谓的平台线程,也就是没有虚拟线程之前,我们一直使用的线程。JVM 调度程序通过平台线程(载体线程)来管理虚拟线程,一个平台线程可以在不同的时间执行不同的虚拟线程(多个虚拟线程挂载在一个平台线程上),当虚拟线程被阻塞或等待时,平台线程可以切换到执行另一个虚拟线程。
虚拟线程、平台线程和系统内核线程的关系图如下所示
使并发编程更加高效和易于使用。虚拟线程是轻量级的线程,运行在平台线程之上,可以大幅提高并发任务的效率。
四种创建虚拟线程的方法:
// 1、通过 Thread.ofVirtual() 创建
Runnable fn = () -> {
};
Thread thread = Thread.ofVirtual(fn)
.start();
// 2、通过 Thread.startVirtualThread() 、创建
Thread thread = Thread.startVirtualThread(() -> {
});
// 3、通过 Executors.newVirtualThreadPerTaskExecutor() 创建
ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
executorService.submit(() -> {
});
class CustomThread implements Runnable {
@Override
public void run() {
System.out.println("CustomThread run");
}
}
//4、通过 ThreadFactory 创建
CustomThread customThread = new CustomThread();
// 获取线程工厂类
ThreadFactory factory = Thread.ofVirtual().factory();
// 创建虚拟线程
Thread thread = factory.newThread(customThread);
// 启动线程
thread.start();
// 等待虚拟线程结束
thread.join()
说明:
- 使用
Thread.startVirtualThread
方法创建虚拟线程,虚拟线程比传统线程更轻量,可以有效利用系统资源,适合大规模并发任务。 - 在JavaSE21转正
结构化并发(Structured Concurrency)
结构化并发旨在简化多线程处理,将相关的任务管理为一个单元,减少线程之间的复杂性和错误。
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> task1 = scope.fork(() -> {
Thread.sleep(1000);
return "Result from task 1";
});
Future<String> task2 = scope.fork(() -> {
Thread.sleep(2000);
return "Result from task 2";
});
scope.join(); // 等待所有任务完成
System.out.println(task1.resultNow());
System.out.println(task2.resultNow());
}
说明:
StructuredTaskScope
允许将并发任务组织为一个结构化的任务组,确保它们的生命周期一致性,减少错误处理的复杂性。
Java20
JDK 20 发布于 2023 年 3 月 21 日。
- JEP 429:作用域值(孵化)
- JEP 432:记录类的模式(第二预览版本)
- JEP 433:使用 switch 的模式匹配(第四预览版本)
- JEP 434:外部函数与内存 API(第二预览版本)
- JEP 436:虚拟线程(第二预览版本)
- JEP 437:结构化并发(第二孵化版本)
- JEP 438:Vector API(第五孵化版本)
Java21
JDK 21 在 2023 年 9 月 19 日发布[319]。与仅预览和孵化 JEP 的 Java 20 相比,Java 21 有 8 个 JEP 不是处于预览或孵化状态。Java 21 正式引入了在 Java 17 和 Java 19 中首次预览的功能(使用 switch 的模式匹配,和记录类的模式)。 x86 上的 32 位 Windows 版本已弃用并删除。
- JEP 430:字符串范本(预览)
- JEP 431:有序的 Collections
- JEP 439:世代 ZGC
- JEP 440:记录类的模式
- JEP 441:使用 switch 的模式匹配
- JEP 442:外部函数与存储器 API(第三预览版本)
- JEP 443:未命名模式和变量(预览)
- JEP 444:虚拟线程
- JEP 445:未命名的类别和实例 main 方法(预览)
- JEP 446:作用域值(预览)
- JEP 448:Vector API(第六孵化版本)
- JEP 449:弃用 Windows 32 位 x86 端口以待后续移除
- JEP 451:准备禁止动态加载代理
- JEP 452:密钥封装机制 API
- JEP 453:结构化并发(预览)
JEP 445 允许main方法位于未命名的类中:
void main() {
System.out.println("Hello, World!");
}
而不用:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
字符串模板(预览)
引入了字符串模板作为孵化器特性,这一特性允许开发者更方便地在字符串中插入和格式化变量。
int x = 5;
int y = 10;
String message = STR."The sum of \\{x} and \\{y} is \\{x + y}.";
System.out.println(message); // 输出 "The sum of 5 and 10 is 15."
序列化集合
https://javaguide.cn/java/new-features/java21.html#jep431-序列化集合
JDK 21 引入了一种新的集合类型:Sequenced Collections(序列化集合,也叫有序集合),这是一种具有确定出现顺序(encounter order)的集合(无论我们遍历这样的集合多少次,元素的出现顺序始终是固定的)。序列化集合提供了处理集合的第一个和最后一个元素以及反向视图(与原始集合相反的顺序)的简单方法。
Sequenced Collections 包括以下三个接口:
SequencedCollection
接口继承了 Collection
接口, 提供了在集合两端访问、添加或删除元素以及获取集合的反向视图的方法。
interface SequencedCollection<E> extends Collection<E> {
// New Method
SequencedCollection<E> reversed();
// Promoted methods from Deque<E>
void addFirst(E);
void addLast(E);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
}
List
和 Deque
接口实现了SequencedCollection
接口。
这里以 ArrayList
为例,演示一下实际使用效果:
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1); // List contains: [1]
arrayList.addFirst(0); // List contains: [0, 1]
arrayList.addLast(2); // List contains: [0, 1, 2]
Integer firstElement = arrayList.getFirst(); // 0
Integer lastElement = arrayList.getLast(); // 2
List<Integer> reversed = arrayList.reversed();
System.out.println(reversed); // Prints [2, 1, 0]
SequencedSet
接口直接继承了 SequencedCollection
接口并重写了 reversed()
方法。
interface SequencedSet<E> extends SequencedCollection<E>, Set<E> {
SequencedSet<E> reversed();
}
SortedSet
和 LinkedHashSet
实现了SequencedSet
接口。
这里以 LinkedHashSet
为例,演示一下实际使用效果:
LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>(List.of(1, 2, 3));
Integer firstElement = linkedHashSet.getFirst(); // 1
Integer lastElement = linkedHashSet.getLast(); // 3
linkedHashSet.addFirst(0); //List contains: [0, 1, 2, 3]
linkedHashSet.addLast(4); //List contains: [0, 1, 2, 3, 4]
System.out.println(linkedHashSet.reversed()); //Prints [5, 3, 2, 1, 0]
SequencedMap 接口继承了 Map接口, 提供了在集合两端访问、添加或删除键值对、获取包含 key 的 SequencedSet、包含 value 的 SequencedCollection、包含 entry(键值对) 的 SequencedSet以及获取集合的反向视图的方法。
interface SequencedMap<K,V> extends Map<K,V> {
// New Methods
SequencedMap<K,V> reversed();
SequencedSet<K> sequencedKeySet();
SequencedCollection<V> sequencedValues();
SequencedSet<Entry<K,V>> sequencedEntrySet();
V putFirst(K, V);
V putLast(K, V);
// Promoted Methods from NavigableMap<K, V>
Entry<K, V> firstEntry();
Entry<K, V> lastEntry();
Entry<K, V> pollFirstEntry();
Entry<K, V> pollLastEntry();
}
SortedMap
和LinkedHashMap
实现了SequencedMap
接口。
这里以 LinkedHashMap
为例,演示一下实际使用效果:
LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");
map.firstEntry(); //1=One
map.lastEntry(); //3=Three
System.out.println(map); //{1=One, 2=Two, 3=Three}
Map.Entry<Integer, String> first = map.pollFirstEntry(); //1=One
Map.Entry<Integer, String> last = map.pollLastEntry(); //3=Three
System.out.println(map); //{2=Two}
map.putFirst(1, "One"); //{1=One, 2=Two}
map.putLast(3, "Three"); //{1=One, 2=Two, 3=Three}
System.out.println(map); //{1=One, 2=Two, 3=Three}
System.out.println(map.reversed()); //{3=Three, 2=Two, 1=One}
Java22
JDK 22 在 2024 年 3 月 19 日发布[323]。
- JEP 423:Region Pinning for G1
- JEP 447:在super()前的语句(预览)
- JEP 454:外部函数和存储器API
- JEP 456:未命名模式和变量
- JEP 457:类别文件API
- JEP 458:启动多个源代码文件程序
- JEP 459:字符串范本(第二预览版本)
- JEP 460:Vector API(第七孵化版本)
- JEP 461:Stream Gatherers(预览)
- JEP 462:结构化并发(第二预览版本)
- JEP 463:未命名的类别和实例 main 方法(第二预览版本)
- JEP 464:作用域值(第二预览版本)
至少有一个 API 已从 Java 中删除;即从 Java 22 中删除了一个很少使用的 API(用于线程)。