常见的下溢和上溢异常

13

我试图在Java中掌握溢出和下溢异常,但是找不到任何好的教程。具体来说,我希望了解以下内容:

  1. 它们之间有什么不同?
  2. 这些异常的子类有哪些?
  3. 在哪种情况下会抛出它们?
  4. 它们中的哪些可以处理,如何处理?
  5. 与它们相关的最佳实践是什么?

任何有用的教程链接都可以。


谢谢你的投票,有什么原因吗?是重复的、不相关的、可维基化的吗? - Ravi Gupta
2
我不是给你点踩的人,但是你说的溢出/下溢是什么类型的呢?算术溢出?栈溢出?还是其他的? - C. K. Young
我希望在这两个异常类上能够有所了解。无论是任何一个,对我来说都会很有用。 - Ravi Gupta
4个回答

30

好的,OP想知道堆栈溢出和算术溢出以及它们的相应下溢的情况。以下是详细解释:

  1. 算术溢出是指数字太大,无法适应其值类型。例如,int类型的值范围在-231到231-1之间(包括两端)。如果您的数字超出了这些限制,就会发生溢出,并且数字“重新开始”。在Java中,这不会引发异常。
  2. 算术下溢是指浮点数变得太小,无法与零区分开来(数字的精度被截断)。在Java中,这也不会引发异常。
  3. 堆栈溢出发生在调用一个函数,该函数再调用另一个函数,然后再调用另一个函数,以此类推...并且函数调用堆栈变得太深时。此时会产生一个StackOverflowError
  4. 在Java中不存在堆栈下溢。其运行时系统应该防止这种情况发生。

回答OP的另一个问题(请参见评论),当您越过数组的边界时,会发出IndexOutOfBoundsException


1
+1清晰的解释。我也听说从int.MIN_VALUE减去1被称为下溢。我以前没有遇到过你提到的第二点。 - Paolo
1
@Paolo:我认为从Integer.MIN_VALUE减去1也被认为是一种溢出。但也许我在这里太过苛求了。 :-) - C. K. Young
@Chris 谢谢,这很有帮助,我在哪里可以获取这方面的文档? - Ravi Gupta
@Ravi:哇,我现在很难给你具体的参考资料,因为很多都是来自于个人经验(我已经用Java编程超过5年了)。嗯。如果你对细节感兴趣,可以(而且应该)尝试阅读Java语言规范。 - C. K. Young
@Chris 我试图在Sun的网站上找到它,但是没有找到我想要的。我会继续寻找,如果找到了,我会在这里发布。 - Ravi Gupta
当数字太大无法适应类型时,就会发生溢出,导致负位指示器被设置,由于Java将负数存储为“二进制补码”,因此这看起来像一个很大的负数。因此,将1添加到2147483647(int max_value)变成了-2147483648。 - Jool

7
在Java算术运算中,溢出或下溢将永远不会抛出异常。相反,在浮点算术中,该值被设置为NaN(不是一个数字)、'无穷大'或零。
要测试这些值,您可以使用适当的包装类调用静态方法:isNaNisInfinite。然后根据需要进行处理。例如:
double d1 = 100 / 0.;
if (Double.isNaN(d1)) {
    throw new RuntimeException("d1 is not a number");
}
if (Double.isInfinite(d1)) {
    throw new RuntimeException("d1 is infinite");
}

在某些操作中,您可能会遇到算术异常,例如在整数运算中除以零时。

我刚刚问了一个相关问题,关于如何以完整的项目方式处理这个问题。


-1 100 / 0 实际上返回的是无穷大,而不是 NaN。此外,算术下溢(非规格化数)会返回 0。 - C. K. Young
谢谢,我对BufferOverflowException和BufferUnderflowException等异常以及相关内容很感兴趣。 - Ravi Gupta
1
@Ravi Gupta - 请将以下内容添加到主要问题中 - BufferOverflowExceptionBufferUnderflowException 比您最初模糊的“溢出和下溢异常”问题更具体。 - Nate
@Feast,这部分是不正确的:“Integer.MAX_VALUE + 2”的结果为“-2147483647”——没有异常,但也不是NaN、无穷大或零。“Double.MAX_VALUE * 2”确实会导致“Infinity”(从数学角度来看,这是一个相当错误的答案;))。 - Andreas Dolk
谢谢,我已经将答案“分成”浮点数和整数部分。 - Pool
显示剩余3条评论

0
由于这是一个非常古老的问题,应该注意到自Java 8以来,Math包提供了“确切”的算术方法,当发生溢出时将触发异常。
例如。
int iv1 = Integer.MAX_VALUE;
int iv2 = Math.addExact(iv1,1);

会触发 java.lang.ArithmeticException:整数溢出。


0
Java没有无符号整数。如果您认为这可能有用,这使得抛出异常变得容易。
public class Counter
{
  private int counter = 0;

  public int increment ()
  {
    counter += 1;
    if (counter < 0)
      throw new RuntimeException ("Counter overflow");
    else
      return counter;
  }

  public String toString() { return String.valueOf(counter); }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接