Bỏ qua để đến nội dung

Tràn số nguyên (Integer Overflow)

Mỗi kiểu số nguyên trong Java có một phạm vi giá trị cố định. Khi kết quả một phép tính vượt quá phạm vi đó, giá trị sẽ “quay vòng” (wrap around) một cách âm thầm, không ném ra lỗi hay cảnh báo gì:

int max = Integer.MAX_VALUE; // 2147483647
System.out.println(max + 1); // -2147483648 - quay vòng về số ÂM nhỏ nhất, KHÔNG có lỗi nào!
byte b = 127; // byte tối đa là 127
b++;
System.out.println(b); // -128 - tràn số âm thầm
  • Không có exception, không có cảnh báo lúc biên dịch hay lúc chạy - chương trình vẫn chạy tiếp với giá trị sai
  • Rất dễ gặp khi nhân hai số int lớn (kết quả trung gian tràn dù kết quả cuối cùng để trong long thì đủ chứa):
int a = 100_000;
int b = 100_000;
long result = a * b; // NGUY HIỂM! a * b được tính bằng int TRƯỚC, tràn số, rồi mới gán sang long
System.out.println(result); // 1410065408 - SAI! (kết quả đúng phải là 10,000,000,000)
  • Thường gặp trong các bài toán tính tổng/tích lớn, tính hash, hoặc bộ đếm chạy lâu dài

1. Ép kiểu sang long trước khi tính, nếu kết quả có thể vượt phạm vi int:

int a = 100_000;
int b = 100_000;
long result = (long) a * b; // ép a sang long TRƯỚC khi nhân -> phép nhân dùng long, không tràn
System.out.println(result); // 10000000000 - ĐÚNG

2. Dùng các phương thức “an toàn” (Math.addExact, Math.multiplyExact,…) để ném exception khi tràn thay vì âm thầm sai:

try {
int result = Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
System.out.println("Phát hiện tràn số: " + e.getMessage());
}

3. Dùng BigInteger nếu cần số nguyên lớn tùy ý, không giới hạn:

import java.math.BigInteger;
BigInteger big = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
System.out.println(big); // vẫn tính đúng, không tràn

Tràn số nguyên: khi kết quả vượt phạm vi kiểu số, Java âm thầm “quay vòng” sang giá trị sai mà không báo lỗi.

  • Ép kiểu sang long/double trước khi tính nếu kết quả trung gian có thể vượt phạm vi int
  • Dùng Math.addExact()/multiplyExact() để phát hiện tràn số bằng exception thay vì âm thầm sai
  • Dùng BigInteger khi cần số nguyên lớn tùy ý