Backend

99 Ngày Java — Ngày 81: var và Type Inference

SSite Admin
16 tháng 10, 2026 3 phút đọc 4 lượt xem
99 Ngày Java — Ngày 81: var và Type Inference

Từ Java 10, biến cục bộ có thể khai báo bằng var và để compiler suy kiểu từ biểu thức khởi tạo. Kiểu vẫn tĩnh, vẫn được kiểm tra lúc biên dịch; thứ thay đổi chỉ là ta không viết lại nó. Vì vậy câu hỏi không phải là var có an toàn không, mà là người đọc có còn thấy đủ thông tin hay không.

var và Type Inference

1. var suy kiểu từ vế phải

Compiler lấy đúng kiểu tĩnh của biểu thức khởi tạo và gán cho biến. Sau đó biến không đổi kiểu được nữa: var không phải kiểu động. var cũng không phải keyword mà là tên kiểu dành riêng, nên code cũ có biến tên var vẫn biên dịch. Dùng được cho biến cục bộ có khởi tạo, biến của for, for-each, try-with-resources, và từ Java 11 cho tham số lambda.

var total = 0;                       // int
var names = new ArrayList<String>(); // ArrayList<String>
for (var name : names) {             // String
    total += name.length();
}
// total = "ten"; // compile error: String cannot be converted to int

2. Những chỗ var bị từ chối

var cần một biểu thức tự mang kiểu. Không có khởi tạo, khởi tạo bằng null, array initializer trần, lambda hay method reference đều không đủ thông tin, vì các dạng này cần kiểu đích. var cũng không dùng cho field, tham số phương thức và kiểu trả về: đó là API của lớp, phải được ghi ra rõ ràng.

// var count;                 // no initializer
// var missing = null;        // null has no useful type
// var ids = {1, 2, 3};       // array initializer needs a type
// var task = () -> run();    // lambda needs a target type
var ids = new int[] {1, 2, 3};   // ok: int[]
Runnable task = () -> run();     // write the functional interface

3. Kiểu được suy ra có thể khác kiểu bạn nghĩ

var lấy kiểu cụ thể của vế phải, không lấy interface: new ArrayList<String>() cho ArrayList<String>, không phải List<String>. Kết hợp var với diamond thì không còn nơi nào cung cấp tham số kiểu, và kết quả là ArrayList<Object>. Số nguyên literal luôn là int; muốn long phải viết hậu tố L. Khi vế phải là lớp ẩn danh, biến mang kiểu không viết ra được nhưng vẫn gọi được thành viên mới của lớp đó.

var list = new ArrayList<>();        // ArrayList<Object>
var orders = new ArrayList<Order>(); // ArrayList<Order>
var size = 1;                        // int, not long or byte
var limit = 1L;                      // long
List<Order> view = orders;           // write the interface when it matters

4. Guideline để code dễ đọc

Hướng dẫn chính thức của OpenJDK xoay quanh một ý: code được đọc nhiều hơn được viết, và người đọc thường không có IDE trên trang review. Dùng var khi vế phải đã nói rõ kiểu, hoặc khi kiểu dài lặp lại không thêm thông tin. Viết kiểu tường minh khi vế phải là lời gọi phương thức có tên mơ hồ.

  • Đặt tên biến mang nghĩa nghiệp vụ: ordersByCustomer nói nhiều hơn map.

  • Giữ phạm vi biến ngắn; biến sống qua nhiều màn hình nên có kiểu tường minh.

  • Cẩn thận với diamond, generic method và số literal vì kiểu suy ra dễ rộng hơn ý định.

  • Không dùng var để giấu một kiểu mà chính bạn cũng không chắc.

var ordersByCustomer = new HashMap<CustomerId, List<Order>>(); // clear
var reader = Files.newBufferedReader(path);                    // clear
var result = service.process(request);                         // what is it?
PaymentResult payment = service.process(request);              // better

var bớt lặp chữ, không bớt kiểu. Hãy để vế phải và tên biến gánh phần thông tin đã bỏ đi. Ngày 82 sang switch expression và pattern matching.

Tài liệu đối chiếu

  • https://openjdk.org/jeps/286

  • https://openjdk.org/projects/amber/guides/lvti-style-guide

S

Site Admin

Engineer and writer. Building things with TypeScript and distributed systems.

Bình luận (0)

Bạn cần đăng nhập bằng Google để bình luận.

Hãy là người bình luận đầu tiên.

Bài viết liên quan

99 Ngày Spring — Ngày 81: WebFlux nhập môn

Blocking so với non-blocking, Mono và Flux, luật không chặn event loop và khi nào reactive thật sự đáng dùng.

16 thg 10, 20263 phút4
99 Ngày Spring — Ngày 80: Saga và Tính nhất quán Dữ liệu

Transactional outbox, saga choreography/orchestration, compensation và consumer idempotent.

15 thg 10, 20262 phút5
99 Ngày Java — Ngày 80: Memory Leak trong Java

Rò rỉ do cache, listener, ThreadLocal và classloader; tìm retained size, GC roots rồi sửa nguồn giữ.

15 thg 10, 20262 phút9