教练, java版本一直更新, 我想了解一下从java8到java17之间的重大变化特征
Java 8:
Lambda 表达式和函数式接口:可以使得代码更加简洁和易读
流式 API:可以用来处理集合和数组,可以使得代码更加简洁和易读
Optional 类型:可以避免空指针异常,可以使得代码更加健壮和可读
接口默认方法:可以使得接口的演化更加灵活和兼容性更好
Date/Time API:可以更加方便地处理日期和时间,可以避免旧的 Date 类型的一些问题
CompletableFuture: 提供了一种简单的方式来处理异步任务
Java 9:
模块化系统:可以用来管理和组织 Java 应用程序的代码,可以使得应用程序更加健壮和可维护
HTTP/2 客户端:内置的 HTTP/2 客户端,可以提高通信性能和可靠性
进程 API:可以用来管理和控制本地进程,可以使得应用程序更加灵活和可控
安全性增强:支持 TLS 1.2 和 TLS 1.3 协议,增强了 XML 处理的安全性,增强了强密码算法的支持,等等,可以使得 Java 应用程序更加安全
新的 GC: 引入了 G1 垃圾回收器作为默认的垃圾回收器,它可以更好地处理大型堆
Java 10:
局部变量类型推断:可以使得代码更加简洁和易读
推断类型变量:可以在一些场景下省略类型变量,可以使得代码更加简洁和易读
Unicode 10.0 支持:可以处理更多的字符集和语言
Java 11:
ZGC低延迟垃圾回收器:可以使得应用程序的响应更加快速和可靠, 可以在数毫秒的时间内处理数百 GB 的堆
HTTP/2 服务器:内置的 HTTP/2 服务器,可以提供高性能的 Web 服务
嵌套访问控制:可以使得在类内部更加灵活地控制访问权限
Java 12:
Java 13:
Text Blocks:可以使得多行字符串的编写更加方便和易读
Switch 表达式增强:可以在 Switch 表达式中使用 Yield 语句,可以使得代码更加灵活和易读
线程局部握手: 引入了线程局部握手 API,使得开发人员可以更加灵活地管理线程局部状态
Java 14:
Records 类型:可以用来定义不可变数据对象,可以使得代码更加简洁和易读
JFR 飞行器:可以用来监控和调优 Java 应用程序,可以提高应用程序的性能和可靠性
Java 15:
Java 16:
静态成员类的上下文引用:可以在静态成员类中使用外部类的 this 引用,可以使得代码更加灵活和易读。
本地变量类型推断升级:可以在更多的场景下使用,可以使得代码更加简洁和易读。
Vector API: 引入了 Vector API,一种用于高性能数值计算的 API
Java 17:
Java 8 引入了 CompletableFuture 类,提供了一种简单的方式来处理异步任务。CompletableFuture 可以用来处理异步任务的结果,还可以将多个异步任务组合在一起。
示例代码:
// 使用 CompletableFuture 处理异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 异步任务
return "Hello World";
});
future.thenAccept(result -> {
// 处理异步任务的结果
System.out.println(result);
});
使用 CompletableFuture 可以使得异步任务更加容易处理,但是要注意避免死锁和线程安全问题。
Java 8 引入了全新的日期和时间 API,可以更加方便地进行日期和时间的处理。Date/Time API 支持时区和夏令时,也提供了一些方便的方法来处理日期和时间。
示例代码:
// 使用 LocalDate 进行日期的操作
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
System.out.println("Today: " + today);
System.out.println("Tomorrow: " + tomorrow);
Date/Time API 中的类都是不可变的,因此它们是线程安全的。
引入了 G1 垃圾回收器作为默认的垃圾回收器,它可以更好地处理大型堆。G1 垃圾回收器可以将堆分成多个区域,以便更加高效地执行垃圾回收
使用 G1 垃圾回收器可以提高大型应用程序的性能,但是要注意避免过多使用内存。
全新的 HTTP/2 客户端 API,可以帮助开发人员更轻松地使用 HTTP/2 协议,从而提高网络通信的效率和性能。
Java 9 的 HTTP/2 客户端 API 包含了以下特性:
非阻塞的 API:HTTP/2 客户端 API 提供了一个非阻塞的 API,可以更好地利用底层的异步 I/O 机制,从而提高网络通信的效率和性能。
流式处理 API:HTTP/2 客户端 API 提供了一个流式处理的 API,可以更轻松地处理大量的 HTTP/2 流,从而提高网络通信的吞吐量和响应速度。
支持 WebSocket:HTTP/2 客户端 API 支持 WebSocket 协议,可以更轻松地实现双向通信和实时通信的功能。
下面是一个简单的示例,展示了如何使用 HTTP/2 客户端 API:
import java.net.URI;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Http2ClientExample {
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create("https://www.example.com"))
.build();
CompletableFuture<HttpResponse<String>> responseFuture = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString());
HttpResponse<String> response = responseFuture.get(10, TimeUnit.SECONDS);
System.out.println(response.body());
}
}
在这个示例中,使用 HTTP/2 客户端 API 发送一个 HTTP GET 请求,获取 https://www.example.com 网站的响应结果,并将响应结果打印到控制台上。使用 HTTP/2 客户端 API,只需要创建一个 HttpClient 实例,并使用 sendAsync() 方法发送异步请求,即可轻松地发送 HTTP/2 请求,并处理 HTTP/2 响应。
它可以帮助开发人员更好地管理代码和依赖项。模块化系统将代码划分为模块,每个模块都可以指定依赖项和可见性。
创建一个新的 Java 9 项目,创建一个名为 mymodule
的模块,并在该模块中创建一个名为 com.example.mymodule
的包,以及一个名为 MyClass
的类:
├── mymodule
│ ├── src
│ │ ├── com.example.mymodule
│ │ │ └── MyClass.java
│ │ └── module-info.java
│ └── test
│ └── com.example.mymodule
│ └── MyClassTest.java
└── pom.xml
在 module-info.java
文件中,声明 mymodule
模块依赖于 java.base
模块,并导出 com.example.mymodule
包:
module mymodule {
requires java.base;
exports com.example.mymodule;
}
在 MyClass.java
文件中,实现一个简单的类,用于打印一句话:
package com.example.mymodule;
public class MyClass {
public void sayHello() {
System.out.println("Hello from com.example.mymodule!");
}
}
在 MyClassTest.java
文件中,编写一个简单的测试类,用于测试 MyClass
类的 sayHello()
方法:
package com.example.mymodule;
import org.junit.jupiter.api.Test;
class MyClassTest {
@Test
void sayHello() {
MyClass myClass = new MyClass();
myClass.sayHello();
}
}
然后,创建一个新的模块 myapp
,用于引用 mymodule
模块中的代码:
├── myapp
│ ├── src
│ │ └── com.example.myapp
│ │ └── MyApp.java
│ └── test
│ └── com.example.myapp
│ └── MyAppTest.java
└── pom.xml
在 module-info.java
文件中,声明 myapp
模块依赖于 mymodule
模块:
module myapp {
requires mymodule;
}
在 MyApp.java
文件中,编写一个简单的类,用于引用 mymodule
模块中的 MyClass
类:
package com.example.myapp;
import com.example.mymodule.MyClass;
public class MyApp {
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.sayHello();
}
}
在 MyAppTest.java
文件中,编写一个简单的测试类,用于测试 MyApp
类的 main()
方法:
package com.example.myapp;
import org.junit.jupiter.api.Test;
class MyAppTest {
@Test
void main() {
MyApp.main(new String[]{});
}
}
局部变量类型推断。这个特性可以让程序员在不明确指定变量类型的情况下,根据变量的初始值来推断变量的类型。这样可以使得代码更加简洁、易读和易维护。
在 Java 10 中,可以使用关键字 var 来声明一个局部变量,然后根据变量的初始值来自动推断变量的类型。使用 var 声明的变量的类型是由编译器自动推断的,可以是任何有效的 Java 类型,包括基本类型和引用类型。
下面是一个简单的示例,展示了如何使用局部变量类型推断:
import java.util.*;
public class LocalVariableTypeInference {
public static void main(String[] args) {
var list = new ArrayList<String>();
list.add("apple");
list.add("banana");
list.add("orange");
var iterator = list.iterator();
while (iterator.hasNext()) {
var element = iterator.next();
System.out.println(element);
}
}
}
在这个示例中,使用 var 声明了一个 ArrayList 和一个 Iterator,然后使用 while 循环遍历集合中的元素,并使用 var 声明了一个变量 element,用于保存迭代器返回的元素。编译器可以根据集合中的元素类型来自动推断 element 的类型为 String。
需要注意的是,局部变量类型推断可以使得代码更加简洁,但也可能会导致可读性下降和代码难以理解。因此,需要在使用时谨慎考虑,避免滥用局部变量类型推断。同时,需要注意,局部变量类型推断只适用于局部变量,不适用于方法的参数、方法的返回值、类的成员变量和静态变量等。
ZGC,一种低延迟的垃圾回收器,可以在数毫秒的时间内处理数百 GB 的堆。ZGC 可以并发执行垃圾回收,减少应用程序的停顿时间。
引入了一个内置的 HTTP/2 服务器,可以用来替代传统的基于 Servlet 容器的 HTTP 服务器。这个 HTTP/2 服务器可以提供更高效、更安全和更灵活的 Web 服务。
HTTP/2 是 HTTP/1 的一种新版本,它可以通过多路复用和二进制协议等特性,提高网络传输效率和安全性,支持更多的流量和更快的速度。Java 11 的 HTTP/2 服务器可以支持以下特性:
多路复用:HTTP/2 服务器可以使用一个 TCP 连接同时处理多个请求和响应,提高了网络传输效率和速度。
流量控制:HTTP/2 服务器可以根据客户端的需求和网络状况,自动控制数据的传输速度和流量。
服务器推送:HTTP/2 服务器可以主动向客户端推送资源,提高了客户端的访问速度和响应性。
安全性增强:HTTP/2 服务器可以使用 TLS 加密协议,保护传输过程中的数据安全性。
下面是一个简单的示例,展示了如何使用 Java 11 的 HTTP/2 服务器:
import com.sun.net.httpserver.*;
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class Http2Server {
public static void main(String[] args) throws IOException {
int port = 8080;
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
server.createContext("/", new MyHandler());
server.setExecutor(Executors.newFixedThreadPool(10));
server.start();
System.out.println("Server is listening on port " + port);
}
static class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
String response = "Hello, world!";
exchange.sendResponseHeaders(200, response.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
在这个示例中,定义了一个 Http2Server 类,它使用 HttpServer 类创建一个 HTTP/2 服务器,并指定监听的端口号。创建了一个 MyHandler 类来处理请求,并返回一个 “Hello, world!” 的字符串。然后使用 Executors 类创建一个线程池来处理请求,并启动 HTTP/2 服务器。
Java 11 的 HTTP/2 服务器可以提供更高效、更安全和更灵活的 Web 服务,尤其是在处理大量的并发请求时,可以提高性能和可伸缩性。
嵌套访问控制,可以使得在类内部更加灵活地控制访问权限。嵌套访问控制可以将一个类的访问控制扩展到另一个类中。
示例代码:
// 使用嵌套访问控制
public class Outer {
private int value;
public class Inner {
private void setValue(int value) {
Outer.this.value = value;
}
}
}
使用嵌套访问控制可以使得代码更加清晰和可维护,但是要注意遵循最佳实践和避免滥用访问控制。
Java 12 引入了新的 switch 语法,使得在 switch 语句中可以使用更加灵活的语法。新的 switch 语法支持使用表达式作为 case 标签,还支持使用箭头语法进行多个标签的组合。
示例代码:
// 使用新的 switch 语法
String fruit = "apple";
int price = switch (fruit) {
case "apple", "pear" -> 2;
case "orange", "banana" -> 3;
default -> 0;
};
System.out.println(price);
使用新的 switch 语法可以使得代码更加简洁和易读,但是要注意避免滥用新语法。
Shenandoah 垃圾回收器是 Java 12 中引入的一种新的垃圾回收器,它是一种低暂停时间垃圾回收器,可以在几乎不会停顿的情况下进行大规模的内存回收。
Shenandoah 垃圾回收器的主要特点包括:
低停顿时间:Shenandoah 垃圾回收器采用了一种新的垃圾回收算法,可以在几乎不会停顿的情况下进行内存回收,从而提高了应用程序的响应性和性能。
大规模内存回收:Shenandoah 垃圾回收器可以在大规模的内存回收时仍然保持低停顿时间,并且不需要额外的内存空间来进行垃圾回收。
跨全局存储区的并发标记:Shenandoah 垃圾回收器使用了一种新的算法来进行并发标记,并且可以在跨全局存储区时仍然保持低停顿时间。
需要注意的是,Shenandoah 垃圾回收器是一种实验性的功能,需要使用 -XX:+UnlockExperimentalVMOptions 参数来启用。并且,它并不适用于所有的应用程序和场景,需要根据实际情况进行评估和测试。在某些场景下,可能会导致性能下降或内存使用增加。
Text Blocks,一种用于编写多行字符串的新语法。Text Blocks 可以使得多行字符串的编写更加方便和易读。
// 使用 Text Blocks
String html = """
Hello, World!
""";
System.out.println(html);
Switch 表达式的增强功能。Switch 表达式可以用来根据不同的值执行不同的代码块,可以替代一系列的 if-else 语句。Switch 表达式的增强功能可以使得代码更加简洁、易读和高效。
具体来说,Switch 表达式的增强功能包括:
简化的 Switch 表达式:可以在一个表达式中使用 Switch,而不需要使用单独的语句。使用 -> 运算符可以将 Switch 的每个 case 语句映射到一个表达式,可以使得代码更加简洁。
多个 case 语句共享代码块:可以使用逗号将多个 case 语句组合到一起,共享同一个代码块。
新的 yield 关键字:可以在 Switch 表达式中使用新的 yield 关键字来返回一个值。yield 语句可以放在一个 case 语句的结尾,表示这个 case 语句返回一个值。
下面是一个简单的示例,展示了如何使用 Switch 表达式的增强功能:
public class SwitchEnhancement {
public static void main(String[] args) {
int day = 3;
String dayType = switch (day) {
case 1, 2, 3, 4, 5 -> "weekday";
case 6, 7 -> "weekend";
default -> throw new IllegalArgumentException("Invalid day: " + day);
};
System.out.println(dayType);
}
}
在这个示例中,定义了一个 SwitchEnhancement 类,它包含一个 main 方法,该方法使用 Switch 表达式来根据不同的值返回不同的字符串。使用逗号将多个 case 语句组合到一起,共享同一个代码块。使用默认语句抛出一个异常,表示如果 day 的值不在 1 到 7 之间,则抛出一个异常。
Switch 表达式的增强功能可以使得代码更加简洁、易读和高效,尤其是在处理大量的 if-else 语句时,可以提高代码的可读性和可维护性。
线程局部握手 API,使得开发人员可以更加灵活地管理线程局部状态。线程局部握手可以在线程启动时设置一个默认值,也可以在运行时动态更改值。
示例代码:
// 使用线程局部握手 API
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("Hello World");
Runnable runnable = () -> {
String value = threadLocal.get();
System.out.println(value);
};
new Thread(runnable).start();
使用线程局部握手可以使得线程间的数据共享更加安全和可控,但是要注意避免过多使用线程局部状态。
Records 类型,一种新的数据类型,可以更加方便地定义不可变的数据类。Records 类型提供了一种简洁的方式来定义只包含数据的类,可以自动为所有属性生成 getter 方法和 equals/hashCode 方法。
// 定义一个 Records 类型
public record Person(String name, int age) {}
// 使用 Records 类型
Person person = new Person("Alice", 20);
System.out.println(person.name());
System.out.println(person.age());
使用 Records 类型可以使得代码更加简洁和易读,但是要注意避免过度使用 Records 类型。
JFR(Java Flight Recorder)飞行器,这是一个用于监控和调优 Java 应用程序的工具。JFR 可以记录应用程序的运行时行为和性能指标,可以用来分析和优化应用程序的性能。
示例代码:
// 启用 JFR 飞行器
java -XX:StartFlightRecording
使用 JFR 飞行器可以使得监控和调优应用程序更加方便和高效,但是要注意遵循最佳实践和避免滥用 JFR 飞行器。
需要注意的是,JFR 飞行器是 Oracle JDK 的一个商业特性,需要付费许可证才能使用。但是,OpenJDK 也提供了一个开源的替代品,称为 JMC(Java Mission Control),可以用来监控和调优 Java 应用程序。
rm -rf 哈哈哈 这个walk我怎么觉得跟python有点相似呀
新的 API,可以进行递归式的删除文件,包括目录和非空目录。这个 API 是通过 java.nio.file.Files 类的 delete(Path path) 方法来实现的,它可以删除指定路径下的文件或目录,并且可以递归删除目录中的所有子目录和文件。
下面是一个简单的示例,展示了如何使用这个 API 进行递归式删除文件:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileDeleter {
public static void main(String[] args) throws IOException {
Path directory = Paths.get("C:/temp");
deleteDirectory(directory);
}
private static void deleteDirectory(Path directory) throws IOException {
Files.walk(directory)
.sorted((path1, path2) -> -path1.compareTo(path2))
.forEach(path -> {
try {
Files.delete(path);
} catch (IOException e) {
System.err.printf("Failed to delete %s. %s", path, e.getMessage());
}
});
}
}
在这个示例中,定义了一个 FileDeleter 类,它包含一个 deleteDirectory 方法,该方法接受一个目录的路径,然后使用 Files.walk() 方法来递归遍历目录下的所有子目录和文件。使用 sorted() 方法按照反向顺序排序,确保删除子目录时,先删除子目录中的文件。最后使用 forEach() 方法来逐个删除目录下的所有文件和子目录,如果删除失败,则输出错误信息。
需要注意的是,递归删除文件可能会很慢,并且如果使用不当可能会意外删除重要文件,因此需要小心使用这个 API,确保正确地删除指定的文件和目录。
对静态成员类进行了增强,可以在静态成员类中使用外部类的 this 引用,可以使得代码更加灵活和易读
Java 14 引入了本地变量类型推断,可以使得代码更加简洁和易读。Java 16 对本地变量类型推断进行了升级,可以在更多的场景下使用
// 使用升级后的本地变量类型推断
var list = new ArrayList<String>();
使用本地变量类型推断可以使得代码更加简洁和易读,但是要注意遵循最佳实践和避免滥用类型推断。
Vector API,一种用于高性能数值计算的 API。Vector API 可以用来执行各种数值计算,例如矩阵乘法和傅里叶变换。
// 使用 Vector API 计算两个向量的点积
int[] a = {1, 2, 3, 4};
int[] b = {5, 6, 7, 8};
IntVector va = IntVector.fromArray(a, 0);
IntVector vb = IntVector.fromArray(b, 0);
int dotProduct = va.dotProduct(vb);
System.out.println(dotProduct);
使用 Vector API 可以提高数值计算的性能和效率,但是要注意避免使用过多的内存
对 Records 类型进行了增强,可以更加灵活地定义 Records 类型。Records 类型现在可以有非 final 的字段和构造函数。
// 使用增强的 Records 类型
public record Person(String name, int age) {
String fullName() {
return name + " (" + age + ")";
}
}
使用 Records 类型可以使得代码更加简洁和易读,但是要注意遵循最佳实践和避免滥用 Records 类型。
它可以用来限制一个类的子类,只有在预定义的一组类中才能被创建。这个特性可以增加代码的安全性、可维护性和可读性。
Sealed 类型可以通过在类声明中使用 sealed 关键字来定义,然后在这个类的子类中使用 permits 关键字来声明哪些子类可以被创建。需要注意的是,如果一个类被定义为 sealed 类型,那么它的所有子类必须是 final 类型或者是另一个 sealed 类型。
下面是一个简单的示例,展示了如何使用 Sealed 类型:
sealed interface Shape permits Circle, Rectangle {
double area();
}
final class Circle implements Shape {
private final double radius;
public Circle(double radius) {
this.radius = radius;
}
public double area() {
return Math.PI * radius * radius;
}
}
final class Rectangle implements Shape {
private final double width;
private final double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double area() {
return width * height;
}
}
在这个示例中,定义了一个 Shape 接口,并使用 sealed 关键字声明它是一个 Sealed 类型,并使用 permits 关键字声明它只允许 Circle 和 Rectangle 类来实现这个接口。然后,定义了 Circle 和 Rectangle 两个类,它们都实现了 Shape 接口,并定义了它们的 area 方法来计算面积。
这个示例展示了如何使用 Sealed 类型来限制一个接口的实现类,并且可以方便地在编译期间检查出不符合要求的子类。这个特性可以帮助开发人员更好地管理类的继承关系,并提高代码的可读性和可维护性。