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.

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 int2. 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 interface3. 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 matters4. 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); // bettervar 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
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.


