Chà, theo như các kiểu số nguyên nguyên, Java hoàn toàn không xử lý Over / Underflow (đối với float và nhân đôi hành vi là khác nhau, nó sẽ tuôn ra +/- vô hạn như các nhiệm vụ của IEEE-754).
Khi thêm hai int, bạn sẽ không nhận được dấu hiệu nào khi xảy ra tràn. Một phương pháp đơn giản để kiểm tra tràn là sử dụng loại lớn hơn tiếp theo để thực sự thực hiện thao tác và kiểm tra xem kết quả có còn trong phạm vi cho loại nguồn không:
public int addWithOverflowCheck(int a, int b) {
// the cast of a is required, to make the + work with long precision,
// if we just added (a + b) the addition would use int precision and
// the result would be cast to long afterwards!
long result = ((long) a) + b;
if (result > Integer.MAX_VALUE) {
throw new RuntimeException("Overflow occured");
} else if (result < Integer.MIN_VALUE) {
throw new RuntimeException("Underflow occured");
}
// at this point we can safely cast back to int, we checked before
// that the value will be withing int's limits
return (int) result;
}
Những gì bạn sẽ làm thay cho các mệnh đề ném, tùy thuộc vào yêu cầu ứng dụng của bạn (ném, tuôn ra tối thiểu / tối đa hoặc chỉ cần đăng nhập bất cứ điều gì). Nếu bạn muốn phát hiện tràn trong các hoạt động dài, bạn không gặp may với người nguyên thủy, thay vào đó hãy sử dụng BigInteger.
Chỉnh sửa (2014-05-21): Vì câu hỏi này dường như được nhắc đến khá thường xuyên và tôi đã phải tự giải quyết vấn đề tương tự, nên việc đánh giá điều kiện tràn bằng phương pháp tương tự mà CPU sẽ tính toán cờ V của nó là khá dễ dàng.
Về cơ bản, nó là một biểu thức boolean liên quan đến dấu của cả hai toán hạng cũng như kết quả:
/**
* Add two int's with overflow detection (r = s + d)
*/
public static int add(final int s, final int d) throws ArithmeticException {
int r = s + d;
if (((s & d & ~r) | (~s & ~d & r)) < 0)
throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");
return r;
}
Trong java đơn giản hơn để áp dụng biểu thức (trong if) cho toàn bộ 32 bit và kiểm tra kết quả bằng cách sử dụng <0 (điều này sẽ kiểm tra hiệu quả bit dấu). Nguyên tắc hoạt động chính xác như nhau cho tất cả các kiểu nguyên nguyên , thay đổi tất cả các khai báo trong phương thức trên thành dài làm cho nó hoạt động lâu dài.
Đối với các loại nhỏ hơn, do chuyển đổi ngầm định thành int (xem JLS để biết chi tiết các thao tác bitwise), thay vì kiểm tra <0, kiểm tra cần che dấu bit rõ ràng (0x8000 cho toán hạng ngắn, 0x80 cho toán hạng byte, điều chỉnh phôi và khai báo tham số thích hợp):
/**
* Subtract two short's with overflow detection (r = d - s)
*/
public static short sub(final short d, final short s) throws ArithmeticException {
int r = d - s;
if ((((~s & d & ~r) | (s & ~d & r)) & 0x8000) != 0)
throw new ArithmeticException("short overflow sub(" + s + ", " + d + ")");
return (short) r;
}
(Lưu ý rằng ví dụ trên sử dụng biểu thức cần để trừ phát hiện tràn)
Vậy làm thế nào / tại sao các biểu thức boolean này hoạt động? Đầu tiên, một số suy nghĩ logic cho thấy rằng một tràn chỉ có thể xảy ra nếu các dấu hiệu của cả hai đối số là như nhau. Bởi vì, nếu một đối số là âm và một đối số dương, kết quả (của add) phải gần bằng 0 hơn hoặc trong trường hợp cực đoan, một đối số bằng 0, giống như đối số khác. Vì các đối số tự chúng không thể tạo điều kiện tràn, nên tổng của chúng cũng không thể tạo ra tràn.
Vậy điều gì xảy ra nếu cả hai đối số có cùng dấu? Hãy xem xét cả hai trường hợp đều dương: thêm hai đối số tạo ra tổng lớn hơn các loại MAX_VALUE, sẽ luôn mang lại giá trị âm, do đó xảy ra tràn nếu arg1 + arg2> MAX_VALUE. Bây giờ giá trị tối đa có thể dẫn đến sẽ là MAX_VALUE + MAX_VALUE (trường hợp cực đoan cả hai đối số là MAX_VALUE). Đối với một byte (ví dụ) có nghĩa là 127 + 127 = 254. Nhìn vào các biểu diễn bit của tất cả các giá trị có thể dẫn đến việc thêm hai giá trị dương, người ta thấy rằng các giá trị tràn (128 đến 254) đều có bit 7, trong khi tất cả những gì không tràn (0 đến 127) đều bị xóa bit 7 (trên cùng, dấu hiệu). Đó chính xác là phần đầu tiên (bên phải) của biểu thức kiểm tra:
if (((s & d & ~r) | (~s & ~d & r)) < 0)
(~ s & ~ d & r) trở thành đúng, chỉ khi , cả hai toán hạng (s, d) đều dương và kết quả (r) là âm (biểu thức hoạt động trên tất cả 32 bit, nhưng bit duy nhất chúng ta quan tâm là bit (dấu) trên cùng, được kiểm tra bằng <0).
Bây giờ nếu cả hai đối số đều âm, tổng của chúng không bao giờ có thể gần bằng 0 hơn bất kỳ đối số nào, tổng phải gần với âm vô hạn. Giá trị cực đoan nhất mà chúng tôi có thể tạo ra là MIN_VALUE + MIN_VALUE, một lần nữa (ví dụ cho byte) cho thấy với bất kỳ giá trị nào trong phạm vi (-1 đến -128), bit dấu được đặt, trong khi mọi giá trị có thể tràn (-129 đến -256 ) đã xóa bit dấu. Vì vậy, dấu hiệu của kết quả một lần nữa cho thấy tình trạng tràn. Đó là những gì nửa bên trái (s & d & ~ r) kiểm tra cho trường hợp cả hai đối số (s, d) đều âm và kết quả là dương. Logic phần lớn tương đương với trường hợp tích cực; tất cả các mẫu bit có thể dẫn đến việc thêm hai giá trị âm sẽ bị xóa bit dấu nếu và chỉ khi xảy ra tràn dòng.