0

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. floatdouble 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 BigDecimal cho 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
  • int không chứa nổi số đó
  • L viết hoa cho dễ nhìn, đùng dùng l nhì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.00.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 Copy và 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 StringBuilder ngầm
  • Inline luôn nếu đơn giản

Ứng dụng:

  • Đừng tối ưu sớm
  • Chỉ dùng StringBuilder khi:
    • 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí