[Java Backend Zero to Hello] BÀI 2.11: JAVA 9-17 FEATURES
📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 2: Java Core Nâng Cao | Bài 26/86
BÀI 2.11: JAVA 9-17 FEATURES
Mục tiêu
- Nắm các tính năng mới từ Java 9 đến 17
- Sử dụng var, record, sealed class
- Áp dụng vào code thực tế
1. TỔNG QUAN CÁC VERSION
| Version | Năm | Tính năng nổi bật |
|---|---|---|
| Java 8 | 2014 | Lambda, Stream, Optional |
| Java 9 | 2017 | Module, Collection factory, private interface method |
| Java 10 | 2018 | var |
| Java 11 | 2018 | LTS, HTTP Client, String methods |
| Java 14 | 2020 | record, switch expression |
| Java 15 | 2020 | sealed (preview), text block |
| Java 16 | 2021 | record, sealed chính thức |
| Java 17 | 2021 | LTS, sealed chính thức |
2. VAR (Java 10+)
Khai báo biến với kiểu được suy luận từ giá trị khởi tạo.
// Trước
String name = "An";
List<Integer> numbers = new ArrayList<Integer>();
// Sau
var name = "An"; // String
var numbers = new ArrayList<Integer>(); // ArrayList<Integer>
var stream = numbers.stream(); // Stream<Integer>
Quy tắc
- Phải khởi tạo ngay khi khai báo
- Không thể khai báo mà không gán:
var x;❌ - Không thể dùng cho field của class
- Không thể dùng cho parameter
// ❌ Không hợp lệ
var x; // Không khởi tạo
var y = null; // Không suy luận được kiểu
var arr = {1, 2, 3}; // Không hợp lệ
// ✅ Hợp lệ
var list = new ArrayList<String>();
var result = computeSomething();
3. RECORD (Java 14+)
Class bất biến (immutable) - tự động sinh constructor, getter, equals, hashCode, toString.
3.1 Khai báo
// Trước - rất dài
public class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public boolean equals(Object o) { /* ... */ }
@Override
public int hashCode() { /* ... */ }
@Override
public String toString() { /* ... */ }
}
// Sau - rất ngắn
public record User(String name, int age) { }
3.2 Sử dụng
User user = new User("An", 25);
String name = user.name(); // "An" - không phải getName()
int age = user.age(); // 25
System.out.println(user); // User[name=An, age=25]
3.3 Thêm method
public record User(String name, int age) {
// Compact constructor - validate
public User {
if (age < 0) {
throw new IllegalArgumentException("Age must be >= 0");
}
}
// Method thường
public boolean isAdult() {
return age >= 18;
}
// Static method
public static User createDefault() {
return new User("Unknown", 0);
}
}
3.4 Khi nào dùng Record
- ✅ DTO, Value Object
- ✅ Response từ API
- ✅ Data transfer giữa các layer
- ❌ Entity JPA (cần mutable)
- ❌ Class có logic phức tạp
4. SEALED CLASS (Java 17+)
Giới hạn class nào được kế thừa.
4.1 Khai báo
public sealed class Shape
permits Circle, Rectangle, Triangle {
public abstract double area();
}
public 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;
}
}
public final class Rectangle extends Shape {
private final double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
}
public final class Triangle extends Shape {
private final double base, height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
}
4.2 Các từ khóa cho class con
final- Không cho kế thừa tiếpsealed- Cho phép kế thừa có giới hạnnon-sealed- Cho phép kế thừa tự do
4.3 Pattern Matching với Sealed
public String describe(Shape shape) {
return switch (shape) {
case Circle c -> "Hình tròn bán kính " + c.radius();
case Rectangle r -> "Hình chữ nhật " + r.width() + "x" + r.height();
case Triangle t -> "Tam giác";
};
}
5. SWITCH EXPRESSION (Java 14+)
Switch trả về giá trị.
// Cũ
String dayName;
switch (day) {
case 1: dayName = "Thứ 2"; break;
case 2: dayName = "Thứ 3"; break;
default: dayName = "Không rõ";
}
// Mới
String dayName = switch (day) {
case 1 -> "Thứ 2";
case 2 -> "Thứ 3";
case 3, 4, 5 -> "Giữa tuần";
case 6, 7 -> "Cuối tuần";
default -> "Không rõ";
};
Với yield
String result = switch (value) {
case 1 -> "Một";
case 2 -> {
System.out.println("Hai");
yield "Hai";
}
default -> "Khác";
};
6. TEXT BLOCK (Java 13+)
Chuỗi nhiều dòng.
String html = """
<html>
<body>
<h1>Hello</h1>
</body>
</html>
""";
String json = """
{
"name": "Java",
"version": 17
}
""";
7. PATTERN MATCHING (Java 16+)
7.1 instanceof
// Cũ
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// Mới
if (obj instanceof String s) {
System.out.println(s.length());
}
7.2 switch với Pattern (Preview)
String formatted = switch (obj) {
case Integer i -> "Integer: " + i;
case Long l -> "Long: " + l;
case Double d -> "Double: " + d;
case String s -> "String: " + s;
case null -> "Null";
default -> "Unknown";
};
8. CÁC METHOD MỚI CỦA STRING
// Java 11+
" Hello ".strip(); // "Hello" - Unicode whitespace
" Hello ".stripLeading(); // "Hello "
" Hello ".stripTrailing(); // " Hello"
"".isEmpty(); // true
" ".isBlank(); // true
"Hello\nWorld".lines().count(); // 2
"Hello".repeat(3); // "HelloHelloHello"
9. COLLECTION FACTORY METHODS (Java 9+)
// Tạo collection immutable ngắn gọn
List<String> list = List.of("A", "B", "C");
Set<Integer> set = Set.of(1, 2, 3);
Map<String, Integer> map = Map.of("A", 1, "B", 2);
// Map.ofEntries cho nhiều entry
Map<String, Integer> map2 = Map.ofEntries(
Map.entry("A", 1),
Map.entry("B", 2),
Map.entry("C", 3)
);
10. HTTP CLIENT (Java 11+)
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
11. BÀI TẬP THỰC HÀNH
Bài 1: DTO với Record
public record UserDTO(
Long id,
String name,
String email,
LocalDateTime createdAt
) {}
public record CreateUserRequest(
@NotBlank String name,
@Email String email,
@Min(0) int age
) {}
Bài 2: Sealed Class cho Response
public sealed interface ApiResponse<T>
permits Success, Error {
record Success<T>(T data) implements ApiResponse<T> {}
record Error<T>(String message, int code) implements ApiResponse<T> {}
}
public String handle(ApiResponse<?> response) {
return switch (response) {
case ApiResponse.Success<?> s -> "Data: " + s.data();
case ApiResponse.Error<?> e -> "Error: " + e.message();
};
}
Bài 3: HTTP Client
public String fetchData(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString()
);
return response.body();
}
12. TÓM TẮT
| Tính năng | Version | Mô tả |
|---|---|---|
var |
10 | Suy luận kiểu local |
record |
14 | Class immutable ngắn gọn |
sealed |
17 | Giới hạn kế thừa |
| Switch expression | 14 | Switch trả về giá trị |
| Text block | 13 | Chuỗi nhiều dòng |
| Pattern matching | 16 | instanceof + switch |
| HTTP Client | 11 | Gọi HTTP hiện đại |
| Collection factory | 9 | List.of(), Set.of() |
Bài tiếp theo: 2.12 Bài tập cuối Phase 2
🧭 Điều Hướng Series
⬅️ Bài trước: BÀI 2.10: ENUM & NESTED CLASS
📋 Lộ trình tổng quan: Xem Toàn Bộ Series
➡️ Bài tiếp theo: BÀI 2.12: BÀI TẬP CUỐI PHASE 2
All rights reserved