Chuyển tới nội dung chính

Java hiện đại: Tổng quan

Mục tiêu bài học

Sau bài này, bạn sẽ:

  • Hiểu được chu kỳ phát hành mới của Java (time-based releases)
  • Nắm được sự khác biệt giữa LTS và non-LTS versions
  • Biết được các tính năng chính từ Java 9 đến Java 21
  • Hiểu được Module System và lợi ích của nó
  • Lên kế hoạch migration giữa các phiên bản Java

Giới thiệu

Java đã trải qua những thay đổi lớn trong cách phát hành và phát triển kể từ năm 2017. Việc hiểu rõ các phiên bản Java hiện đại và tính năng của chúng là quan trọng để viết code hiệu quả và maintainable.

💡 Hình dung: Java release cycle giống như smartphone — mỗi năm có model mới (Java 18, 19, 20...), nhưng chỉ một số là flagship được hỗ trợ lâu dài (LTS: Java 11, 17, 21). Bạn không cần mua flagship mới mỗi năm, nhưng nên upgrade khi flagship hiện tại sắp hết hỗ trợ.

Java Release Cycle (Chu kỳ phát hành)

Trước Java 10: Feature-based releases

Trước khi Java 10 ra mắt, Java có chu kỳ phát hành không cố định:

  • Java 7 (2011): Mất 5 năm sau Java 6
  • Java 8 (2014): Mất 3 năm sau Java 7
  • Java 9 (2017): Mất 3 năm sau Java 8

Từ Java 10 trở đi: Time-based releases

Kể từ Java 10 (March 2018), Oracle áp dụng chu kỳ phát hành mới:

Đặc điểmChi tiết
Chu kỳ6 tháng/phiên bản
Lịch trìnhTháng 3 và Tháng 9 hàng năm
Feature freezeTính năng không hoàn thành sẽ chuyển sang phiên bản sau
Preview featuresCác tính năng thử nghiệm, có thể thay đổi
Lợi ích của chu kỳ 6 tháng
  • Faster innovation: Tính năng mới đến tay developer nhanh hơn
  • Predictable schedule: Dễ dàng lên kế hoạch migration
  • Smaller changes: Mỗi release ít thay đổi hơn, dễ nâng cấp
  • Preview features: Nhận feedback sớm từ cộng đồng

Quy trình phát hành tính năng mới

LTS Versions (Long-Term Support)

Không phải phiên bản nào cũng được hỗ trợ lâu dài. Oracle chỉ chọn một số phiên bản làm LTS.

Các phiên bản LTS

Phiên bảnNgày phát hànhEnd of SupportTình trạng
Java 8March 2014December 2030LTS (legacy)
Java 11September 2018September 2026LTS
Java 17September 2021September 2029LTS
Java 21September 2023September 2031LTS (latest)
Phiên bản non-LTS

Các phiên bản không phải LTS (Java 10, 12, 13, 14, 15, 16, 18, 19, 20) chỉ được hỗ trợ 6 tháng cho đến khi phiên bản tiếp theo ra mắt. Chúng KHÔNG phù hợp cho production.

Chu kỳ vòng đời hỗ trợ

Tại sao LTS quan trọng?

// Một công ty sử dụng Java 8 từ 2015
// Năm 2024, họ phải migration sang Java 17 hoặc 21

// Java 8 code
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.filter(name -> name.startsWith("A"))
.forEach(System.out::println);

// Java 17+ code - có thể dùng text blocks, records, var
var names = List.of("Alice", "Bob", "Charlie"); // Immutable list
names.stream()
.filter(name -> name.startsWith("A"))
.forEach(System.out::println);

Lý do chọn LTS:

  1. Long-term support: Hỗ trợ bug fixes và security patches lâu dài
  2. Stability: Phù hợp cho production environments
  3. Third-party compatibility: Libraries/frameworks hỗ trợ tốt hơn
  4. Lower migration cost: Không cần upgrade mỗi 6 tháng

Java Version Timeline

Timeline: Java 9 → 21 Highlights

Mindmap: Modern Java Features theo Danh mục

Java 9 (September 2017) - Modularity

// Module System (Project Jigsaw)
module com.example.myapp {
requires java.sql;
exports com.example.myapp.api;
}

// JShell - Java REPL
$ jshell
jshell> int x = 10
x ==> 10
  • Module System: Chia ứng dụng thành modules
  • JShell: Interactive REPL cho Java
  • Collection factory methods: List.of(), Set.of(), Map.of()

Java 10 (March 2018) - Local Variable Inference

// var keyword
var list = new ArrayList<String>(); // Type inference
var map = Map.of("key", "value"); // Cleaner code

Java 11 (September 2018) - LTS

// New String methods
" Hello ".isBlank(); // false
" Hello ".strip(); // "Hello"
"Java\nKotlin\nScala".lines() // Stream<String>

// var in lambda
(var x, var y) -> x + y

// HttpClient API
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com"))
.build();

Java 12-13 (2019) - Preview features

// Switch expressions (preview in 12, standard in 14)
var day = switch (dayOfWeek) {
case MONDAY, FRIDAY -> 6;
case TUESDAY -> 7;
default -> throw new IllegalArgumentException();
};

Java 14 (March 2020)

// Switch expressions (standard)
// Records (preview)
record Point(int x, int y) {}

Java 15 (September 2020)

// Text Blocks (standard)
String json = """
{
"name": "Alice",
"age": 30
}
""";

Java 16 (March 2021)

// Records (standard)
record Person(String name, int age) {}

// Pattern matching for instanceof (standard)
if (obj instanceof String s) {
System.out.println(s.toUpperCase());
}

Java 17 (September 2021) - LTS

// Sealed classes (standard)
sealed interface Shape permits Circle, Rectangle, Square {}

final class Circle implements Shape {}
final class Rectangle implements Shape {}
final class Square implements Shape {}

// Pattern matching với sealed classes
double area = switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Square s -> s.side() * s.side();
};

Java 18-20 (2022-2023) - Preview features

  • Pattern matching cho switch (preview)
  • Virtual threads (preview)
  • Structured concurrency (preview)

Java 21 (September 2023) - LTS

// Virtual Threads (standard)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> System.out.println("Hello from virtual thread"));
}

// Pattern matching for switch (standard)
String formatted = switch (obj) {
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 -> obj.toString();
};

// Record patterns
record Point(int x, int y) {}
if (obj instanceof Point(int x, int y)) {
System.out.println("x = " + x + ", y = " + y);
}

Migration Considerations

Java 8 → Java 11

Thay đổiImpactAction
Java EE modules removedjavax.xml.bind, javax.activation không cònThêm dependencies riêng
Nashorn deprecatedJavaScript engine cũDùng GraalVM hoặc alternatives
Security changesTLS 1.0/1.1 disabledUpgrade protocols
PerformanceG1GC mặc địnhReview GC settings
// Java 8 - JAXB có sẵn
import javax.xml.bind.JAXBContext;

// Java 11 - Cần thêm dependency
// pom.xml
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>

Java 11 → Java 17

// Có thể dùng:
// - Records thay vì POJOs
// - Sealed classes cho domain modeling
// - Pattern matching cho instanceof
// - Text blocks cho multi-line strings

// Before (Java 11)
public class Person {
private final String name;
private final int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

// getters, equals, hashCode, toString...
}

// After (Java 17)
public record Person(String name, int age) {}
Migration tips
  1. Update dependencies: Frameworks cần phiên bản hỗ trợ Java mới
  2. Test thoroughly: Chạy full test suite
  3. Check third-party libraries: Một số library cũ không tương thích
  4. Review deprecations: @Deprecated(forRemoval=true)

Java 17 → Java 21

// Virtual threads - game changer cho concurrent applications
// Before: Platform threads
ExecutorService executor = Executors.newFixedThreadPool(100);

// After: Virtual threads
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

Key benefits:

  • Virtual threads cho high-throughput I/O
  • Pattern matching improvements
  • Sequenced collections

Module System (Java 9) - Giới thiệu ngắn

Tại sao cần Module System?

Vấn đề trước Java 9:

  • Classpath hell: Conflict giữa các versions của libraries
  • No encapsulation: Tất cả public classes đều accessible
  • Large JRE: JRE chứa nhiều modules không cần thiết

Module cơ bản

// module-info.java
module com.example.app {
// Khai báo dependencies
requires java.sql;
requires java.logging;

// Export packages (public API)
exports com.example.app.api;

// Internal packages không export
// com.example.app.internal - not accessible
}

Ưu điểm

  1. Strong encapsulation: Chỉ export những gì cần thiết
  2. Reliable configuration: Compile-time dependency checking
  3. Smaller runtime: Chỉ include modules cần thiết
  4. Better performance: JVM optimization

Module System — Deep Dive

Kiến trúc Module System

Các directive trong module-info.java

module-info.java — Đầy đủ directives
module com.example.app {
// requires — khai báo dependency
requires java.sql; // Phụ thuộc java.sql
requires transitive java.logging; // Transitive: module dùng app cũng thấy logging
requires static java.compiler; // Optional: chỉ cần lúc compile

// exports — public API
exports com.example.app.api; // Cho TẤT CẢ modules thấy
exports com.example.app.spi to // Chỉ cho modules cụ thể thấy
com.example.plugin;

// opens — cho phép reflection (runtime access)
opens com.example.app.model; // Cho TẤT CẢ — cần cho Jackson, Hibernate
opens com.example.app.config to // Chỉ cho Spring Framework
spring.core, spring.beans;

// uses/provides — ServiceLoader pattern
uses com.example.app.spi.Plugin;
provides com.example.app.spi.Plugin
with com.example.app.DefaultPlugin;
}

requires transitive — Truyền dependency

// module com.example.lib
module com.example.lib {
requires transitive java.sql; // Transitive!
exports com.example.lib.db;
}

// module com.example.app
module com.example.app {
requires com.example.lib;
// KHÔNG cần "requires java.sql" — đã có transitive từ lib
// Code trong app CÓ THỂ dùng java.sql classes
}

Unnamed Module và Automatic Module

Loại moduleMô tảKhi nào gặp
Named modulemodule-info.javaProject mới, JDK modules
Automatic moduleJAR trên module-path, tên từ filenameLibrary chưa modularize
Unnamed moduleCode trên classpath (cũ)Legacy code
# Kiểm tra dependencies với jdeps
jdeps --module-path libs -s myapp.jar

# Thêm quyền truy cập khi bị module system chặn
java --add-opens java.base/java.lang=ALL-UNNAMED MyApp

# Tạo custom runtime image (chỉ chứa modules cần thiết)
jlink --module-path $JAVA_HOME/jmods:myapp.jar \
--add-modules com.example.app \
--output custom-jre
# custom-jre chỉ ~30MB thay vì ~300MB full JDK!

Migration Gotchas

// 1. Split packages — cùng package trong 2 modules
// ❌ Error: Package com.example.util exists in both moduleA and moduleB
// Fix: Merge hoặc rename packages

// 2. Reflection access bị chặn
// ❌ InaccessibleObjectException từ Java 16+
// Fix: --add-opens hoặc "opens" directive

// 3. Internal APIs bị chặn
// ❌ sun.misc.Unsafe không accessible
// Fix: Dùng VarHandle (Java 9+) thay thế
import java.lang.invoke.VarHandle;
OCP Trap — Module System

requires transitive truyền dependency cho module phụ thuộc. Nếu module A requires transitive module B, thì module C chỉ cần requires module A là đã thấy module B.

Unnamed module có thể đọc TẤT CẢ named modules, nhưng named module KHÔNG THỂ requires unnamed module. Đây là lý do migration từ classpath sang module-path phải làm từ dưới lên.

OCP Trap — @Deprecated(forRemoval=true)

@Deprecated(forRemoval=true) khác @Deprecated(since="9"):

  • forRemoval=true: Sẽ bị XOÁ trong phiên bản tương lai → compiler warning mạnh hơn
  • since="9": Chỉ đánh dấu deprecated từ version 9, chưa chắc sẽ bị xoá
@Deprecated(since="9", forRemoval=true)
public class SecurityManager { ... } // SẼ bị xoá (removed in Java 24)

@Deprecated(since="9")
public class Observable { ... } // Deprecated nhưng CHƯA CHẮC bị xoá
📖 Oracle Migration Guide

Oracle khuyến nghị migration theo từng bước: (1) compile với --release flag để phát hiện removed APIs, (2) dùng jdeps để phân tích dependencies, (3) thêm --add-opens cho reflection access, (4) tạo module-info.java khi sẵn sàng.

Tham khảo: Oracle Migration Guide

Module adoption

Module system là optional. Bạn có thể chạy code Java 9+ mà không cần modules (unnamed module). Tuy nhiên, trong dự án lớn, modules giúp quản lý dependencies tốt hơn.

Deprecated Features cần biết

Removed trong Java 11+

  • Applets: Hoàn toàn removed
  • Java Web Start: Removed
  • CORBA: Removed
  • JavaFX: Tách ra thành dự án riêng

Deprecated trong Java 21

// Finalization - deprecated for removal
@Override
protected void finalize() throws Throwable {
// DON'T USE - use try-with-resources instead
}

// Better approach
class Resource implements AutoCloseable {
@Override
public void close() {
// Cleanup logic
}
}

try (var resource = new Resource()) {
// Use resource
} // Automatically closed

Kết luận

Nếu bạn đang dùngNên upgrade lênLý do
Java 8Java 17LTS, modern features, performance
Java 11Java 21Latest LTS, virtual threads
Java 17Java 21Virtual threads, pattern matching improvements
Non-LTS (12-16, 18-20)Java 21End of support
Khuyến nghị
  • Production: Luôn dùng LTS version (hiện tại là Java 17 hoặc 21)
  • Learning: Thử nghiệm với latest version để học tính năng mới
  • Migration: Lên kế hoạch migration từ sớm, test kỹ trước khi production

Tính năng chi tiết trong module này

Các bài tiếp theo sẽ đi sâu vào từng tính năng:

Tính năngBài họcJava Version
var — Local Variable Type Inferencevar keywordJava 10
Text BlocksText BlocksJava 15
RecordsRecordsJava 16
Sealed ClassesSealed ClassesJava 17
Pattern MatchingPattern MatchingJava 16-21
Virtual ThreadsVirtual ThreadsJava 21

Tài liệu tham khảo

Đọc thêm