16 Fact có thể bạn chưa biết trong Java
Hãy đọc và chấm điểm bạn biết được bao nhiêu fact nhé.
1. char không phải ASCII
char là UTF-16 code unit (16 bit).
Nên emoji cần 2 char.
char c = '😊'; // compile error
2. boolean không có size cố định
Java spec không định nghĩa boolean chiếm bao nhiêu bit.
- Trong memory: JVM tự quyết
- Trong array thường là 1 byte
- Không có
Boolean.SIZE
3. Wrapper type có cache ngầm
Integer, Short, Byte, Long, Character có cache sẵn một số giá trị.
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true
Integer x = 128;
Integer y = 128;
System.out.println(x == y); // false
4. == với primitive và wrapper là 2 thế giới khác nhau
int a = 10;
int b = 10;
a == b; // true
Integer c = 10;
Integer d = new Integer(10);
c == d; // false
5. null không phải là data type
- không có type riêng
- Có thể gán cho mọi reference type
- Không thể gán cho primitive type
6. byte, short luôn bị promote khi tính toán
Mọi phép toán số học nhỏ hơn int đèu bị promote lên int
byte a = 10;
byte b = 20;
byte c = a + b; // compile lỗi
Phải viết
byte c = (byte) (a + b);
7. float và double không chính xác như bạn nghĩ
System.out.println(0.1 + 0.2); // 0.30000000000000004
- Dùng IEEE 754
- Không phù hợp cho tiền tệ
- Dùng
BigDecimalcho tài chính
8. long literal phải có L
long x = 10000000000; // compile lỗi
long y = 10000000000L; // ok
Vì:
- Literal số nguyên mặc định là
int intkhông chứa nổi số đóLviết hoa cho dễ nhìn, đùng dùnglnhìn như số1
9. Array của primitive khác với array của wrapper
int[] a = new int[3];
Integer[] b = new Integer[3];
a: [0, 0, 0]b: [null, null, null]
10. -0.0 và 0.0 khác nhau
double a = 0.0;
double b = -0.0;
System.out.println(a == b); // true
System.out.println(1 / a); // Infinity
System.out.println(1 / b); // -Infinity
11. instanceof không bao giờ true với null
Object o = null;
System.out.println(o instanceof String); // false
Không ném exception. Không cảnh báo.
instanceof kiểm tra object tồn tại + đúng kiểu, không phải “có thể là kiểu đó”.
12. final array không hề immutable
final int[] arr = {1, 2, 3};
arr[0] = 99; // OK
// arr = new int[]{4,5,6}; // compile lỗi
final chỉ khoá reference, không khoá nội dung.
13. Objects.requireNonNull() nhanh hơn if (x == null)
Bạn nghĩ tự check null là rẻ? JVM nghĩ khác.
this.user = Objects.requireNonNull(user, "user is required");
- JVM biết đây là null-check chuẩn
- JIT có thể optimize tốt hơn
if - Stacktrace rõ ràng, fail sớm, fail đúng chỗ
- Các framework như Spring dùng cái này không phải vì đẹp mà vì nó hợp tác với JVM.
14. System.arraycopy() nhanh hơn mọ vòng lặp bạn biết
System.arraycopy(src, 0, dest, 0, length);
- Native call: Nó không viết bằng Java. Nó là 1 intrinsic function được triển khai bằng mã máy (C/C++) thông qua JNI.
- Có thể dùng memcpy bên dưới
- JVM biết optimize theo loại array
Ứng dụng:
- Copy buffer
- Xử lý dữ liệu lớn
- Performance-critical code
- Với mảng >10k phần tử. Nó nhanh hơn gấp 2 đến 10 lần so với for thủ công. Nhưng hạn chế là nó chỉ là
Shallow Copyvà thiếu logic so với for.
Viết for (i++) dest[i] = src[i]; là bạn đang tự làm chậm mình, rất chăm chỉ nhưng vô ích.
15. StringBuilder không phải lúc nào cũng cần
String s = "a" + "b" + x + "c";
Trong compile-time, javac có thể:
- Gộp string literal
- Sinh
StringBuilderngầm - Inline luôn nếu đơn giản
Ứng dụng:
- Đừng tối ưu sớm
- Chỉ dùng
StringBuilderkhi:- Loop lớn
- Hot path
- Concatenation động nhiều lần
16. Optional không dành cho field
Spec không cấm, nhưng design intent là:
- Return type
- API boundary
Sai mục đích:
classUser {
Optional<String> name;
}
Đúng mục đích:
Optional<String>getName();
Vì:
- Optional tạo object
- Không serializable tốt
- ORM không thích
- Làm code phức tạp hơn
Optional là để buộc người gọi suy nghĩ, không phải để thay null khắp nơi.
All rights reserved