从JDK 8到JDK 17,Java语言和平台经历了许多变化和改进,引入了许多吸引人的新特性和功能。在这里,给大家列举一些我认为最有趣或最有用的新特性,并会以实际使用案例为大家展示新用法。希望大家多多点赞关注!!
1. JDK 8之Lambda表达式和Stream API
JDK 8带来了许多新的语言特性,其中最引人注目的是Lambda表达式和Stream API。Lambda表达式允许Java开发人员使用更简洁的语法编写函数式代码,这使得代码更易于阅读和维护。Stream API则为Java开发人员提供了一种便捷的方式来处理集合和数据流,使得代码更加简洁和易于理解。
大家可以看下我之前的文章里面对Lambda常用的做了详细介绍。
2. JDK 9之平台模块系统
JDK 9引入了Java平台模块系统,这是一个重大的变化。模块系统允许开发人员将代码组织成模块,并且可以控制模块之间的依赖关系。这使得代码更加模块化,并且可以更好地管理代码库和依赖项,以下是常见的举例:
-
java.base
: 这是Java平台的基本模块,提供了核心的API和功能,包括集合框架、并发工具、I/O操作等。它是其他模块的基础依赖。 -
java.sql
: 这个模块包含了Java数据库连接(JDBC)相关的API和实现,允许开发者与各种关系型数据库进行交互。 -
java.xml
: 这个模块提供了对XML文档的解析和处理功能,包括DOM、SAX等API,使得开发者可以方便地读取和操作XML数据。 -
java.logging
: 这个模块提供了Java的日志记录功能,允许开发者在应用程序中记录和管理日志信息。 -
java.desktop
: 这个模块提供了与桌面应用程序相关的功能,包括AWT(Abstract Window Toolkit)和Swing等用户界面组件。 -
java.management
: 这个模块提供了对Java虚拟机(JVM)管理和监控的API,允许开发者获取和操作JVM的运行时信息。 -
java.net.http
: 这个模块提供了一个简单易用的HTTP客户端API,使得开发者可以方便地发送HTTP请求和处理响应。
3. JDK 10之局部变量类型推断
JDK 10引入了局部变量类型推断,这使得开发人员可以在不显式指定变量类型的情况下声明变量。这使得代码更加简洁,并且可以减少重复的代码。允许在声明局部变量时使用关键字 var 来自动推断变量的类型。这在某些情况下可以简化代码,并提高代码的可读性和编写效率。
以下是一些使用局部变量类型推断的实际例子:
基本类型推断:
var age = 25; // 推断为 int
var pi = 3.14159; // 推断为 double
对象类型推断:
var list = new ArrayList<String>(); // 推断为 ArrayList<String>
var map = new HashMap<Integer, String>(); // 推断为 HashMap<Integer, String>
循环迭代器类型推断:
var numbers = List.of(1, 2, 3, 4, 5);
for (var number : numbers) {
System.out.println(number); // 推断为 Integer
}
Lambda 表达式类型推断:
var runnable = (Runnable) () -> {
System.out.println("Hello, World!"); // 推断为 Runnable
};
try-with-resources 语句类型推断:
try (var reader = new BufferedReader(new FileReader("file.txt"))) {
// 使用 reader 读取文件内容
} catch (IOException e) {
// 处理异常
}
4. JDK 11之HTTP客户端API
JDK 11引入了HTTP客户端API,这是一个全新的HTTP客户端实现。这使得开发人员可以更加轻松地与网络进行交互,并且可以更加灵活地配置和管理HTTP请求。
发送GET请求并获取响应:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class HttpClientExample {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
发送POST请求并获取响应:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpHeaders;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.StandardCharsets;
import java.util.Map;
public class HttpClientExample {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
// 构建请求体
String requestBody = "username=testuser&password=pass123";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/login"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}
发送带有Headers和查询参数的请求:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpHeaders;
public class HttpClientExample {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
// 构建请求URL,包括查询参数
URI uri = URI.create("https://api.example.com/search?query=java");
// 添加Headers
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.header("Authorization", "Bearer XXXXXXXXXXXX")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
5. JDK 12之Switch表达式
JDK 12引入了Switch表达式,这是对传统Switch语句的扩展。Switch表达式允许开发人员以更简洁的方式编写Switch语句,并且可以更容易地处理多个值。
基本用法:
public class SwitchExample {
public static void main(String[] args) {
int dayOfWeek = 3;
String dayType = switch (dayOfWeek) {
case 1, 2, 3, 4, 5 -> "Weekday";
case 6, 7 -> "Weekend";
default -> throw new IllegalArgumentException("Invalid day of week: " + dayOfWeek);
};
System.out.println(dayType); // 输出:Weekday
}
}
返回值和Lambda表达式:
public class SwitchExample {
public static void main(String[] args) {
String fruit = "apple";
int count = switch (fruit) {
case "apple" -> {
System.out.println("Apple is selected.");
yield 5; // 返回数量为 5
}
case "banana" -> {
System.out.println("Banana is selected.");
yield 3; // 返回数量为 3
}
default -> throw new IllegalArgumentException("Unknown fruit: " + fruit);
};
System.out.println("Number of fruits: " + count); // 输出:Number of fruits: 5
}
}
空语句和复用标签:
public class SwitchExample {
public static void main(String[] args) {
String fruit = "orange";
switch (fruit) {
case "apple" -> System.out.println("Apple is selected.");
case "banana" -> {
System.out.println("Banana is selected.");
break;
}
case "orange" -> {
System.out.println("Orange is selected.");
break;
}
default -> throw new IllegalArgumentException("Unknown fruit: " + fruit);
}
// 输出:Orange is selected.
}
}
6. JDK 13之文本块
JDK 13引入了文本块,这是一种新的字符串语法。文本块允许开发人员以更简洁的方式编写多行字符串,这使得代码更加易于阅读和维护。
基本用法:
public class TextBlockExample {
public static void main(String[] args) {
String textBlock = """
Hello,
this is a
text block.""";
System.out.println(textBlock);
}
}
结合变量插入:
public class TextBlockExample {
public static void main(String[] args) {
String name = "Alice";
int age = 25;
String textBlock = """
Person Details:
Name: %s
Age: %d
""".formatted(name, age);
System.out.println(textBlock);
}
}
保留缩进格式:
public class TextBlockExample {
public static void main(String[] args) {
String textBlock = """
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
""";
System.out.println(textBlock);
}
}
转义特殊字符:
public class TextBlockExample {
public static void main(String[] args) {
String textBlock = """
This is a text block with special characters:
- Tab: \t
- Newline: \n
- Backslash: \\
""";
System.out.println(textBlock);
}
}
- JDK 14之Records
JDK 14引入了Records,这是一种新的Java类类型。记录允许开发人员以更简洁的方式定义数据对象,并提供了自动生成的方法,如equals和hashCode方法。
public record Person(String name, int age) {
// 可以在这里添加其他字段、构造函数或方法
public static void main(String[] args) {
Person person = new Person("Alice", 25);
System.out.println(person.name()); // 输出:Alice
System.out.println(person.age()); // 输出:25
// 编译器自动生成的toString()方法
System.out.println(person); // 输出:Person[name=Alice, age=25]
Person otherPerson = new Person("Alice", 25);
// 编译器自动生成的equals()方法
System.out.println(person.equals(otherPerson)); // 输出:true
}
}
在上面的示例中,Person是一个记录类,由关键字record来声明。它包含了两个字段name和age,并自动提供了相应的访问方法。此外,编译器还自动生成了equals()、hashCode()和toString()等方法,用于比较对象的相等性和生成字符串表示。
使用记录类可以更轻松地定义简单的数据封装类,避免手动编写大量的样板代码。记录类的字段默认是不可变的(final),在创建对象后无法修改其值。这使得记录类非常适合表示数据传输对象(DTO)或值对象(Value Object)。
8. JDK 15之Sealed Classes
JDK 15引入了Sealed Classes,这是一种新的类类型。封闭类允许开发人员限制类的继承,使得代码更加可靠和安全。
下面是使用JDK 15的Sealed Classes的一个示例:
public sealed class Shape permits Circle, Rectangle {
// 可以在这里添加通用的方法或字段
// 密封类中的方法可供子类选择性地重写
public double area() {
return 0;
}
}
final class Circle extends Shape {
private final double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
final class Rectangle extends Shape {
private final double length;
private final double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public double area() {
return length * width;
}
}
在上面的示例中,Shape是一个密封类,使用关键字sealed进行声明。Shape类使用permits关键字明确指定了允许继承的子类有Circle和Rectangle。这意味着除了这两个子类,其他类无法直接继承自Shape。
Circle和Rectangle是Shape的两个子类,它们分别表示圆和矩形。子类必须为密封类声明的方法提供实现。在示例中,Circle通过重写area()方法来计算圆的面积,Rectangle则通过重写area()方法来计算矩形的面积。
使用密封类可以限制继承的范围,提供更严格的类型检查和更安全的代码。在某些情况下,密封类还可以增加可读性和可维护性,使代码结构更清晰。
9. JDK 16之Pattern Matching for instanceof
JDK 16引入了Pattern Matching for instanceof(instanceof的模式匹配)的特性,它简化了对对象类型的判断和转换的代码。通过使用instanceof关键字和模式匹配,可以更方便地进行类型检查和类型转换,减少样板代码的编写。
下面是使用JDK 16的Pattern Matching for instanceof的一个示例:
public class Example {
public static void main(String[] args) {
Object obj = "Hello";
if (obj instanceof String str) {
System.out.println(str.length()); // 输出:5
// 通过模式变量直接访问匹配后的对象
System.out.println(str.toUpperCase()); // 输出:HELLO
} else {
System.out.println("Object is not a String");
}
}
}
在上面的示例中,我们有一个Object类型的对象obj,我们想要判断它是否是一个String类型的实例。在使用instanceof进行类型检查时,我们在判断条件的同时,通过使用as关键字创建了一个模式变量str,并将匹配成功的对象赋值给它。
如果obj是一个String类型的实例,那么就会执行if语句块内的代码。在这里,我们可以直接使用模式变量str来调用String类的方法,例如length()
和toUpperCase()
。
如果obj不是一个String类型的实例,那么就会执行else语句块内的代码。
使用Pattern Matching for instanceof
可以更清晰地表达类型判断和转换的逻辑,减少了临时变量的使用,并使代码更加简洁。它提供了更高效、更安全的方式来处理对象类型的判断和转换。
10. JDK 17之弱引用垃圾回收器
JDK 17引入了许多新的功能和改进,其中包括弱引用垃圾回收器,ZGC的大型页支持和预测性空闲列表分配,以及JVM日志记录API的改进。
总的来说,JDK 8到JDK 17带来了许多令人兴奋的新特性和功能。这些新特性和功能使得Java开发更加容易、高效和有趣,同时也使得Java语言和平台更加强大和灵活。
今天将JDK 8到JDK 17的一些比较重大的改进和新特性就给大家分享到这里,希望大家多多点赞关注!后续会给大家持续分享技术知识,让我们一起进步!!