Java如何处理整数下溢和溢出?
在此之后,您将如何检查/测试这是否正在发生?
在几种现代编程语言(包括C++,Java和C#)中,该语言允许在运行时发生整数溢出,而不会引发任何类型的错误条件.
例如,考虑这个(人为的)C#方法,它没有考虑上溢/下溢的可能性.(为简洁起见,该方法也不处理指定列表为空引用的情况.)
//Returns the sum of the values in the specified list.
private static int sumList(List<int> list)
{
int sum = 0;
foreach (int listItem in list)
{
sum += listItem;
}
return sum;
}
Run Code Online (Sandbox Code Playgroud)
如果调用此方法如下:
List<int> list = new List<int>();
list.Add(2000000000);
list.Add(2000000000);
int sum = sumList(list);
Run Code Online (Sandbox Code Playgroud)
sumList()方法中将发生溢出(因为intC#中的类型是32位有符号整数,并且列表中值的总和超过了最大32位有符号整数的值).sum变量的值为-294967296(不是值4000000000); 这很可能不是sumList方法的(假设的)开发人员所期望的.
显然,开发人员可以使用各种技术来避免整数溢出的可能性,例如使用类似Java的类型BigInteger,或者使用C#中的checked关键字和/checked编译器开关.
但是,我感兴趣的问题是为什么这些语言默认设计为允许整数溢出首先发生,而不是例如在运行时执行操作时引发异常,从而导致溢出.看起来这种行为有助于避免在编写执行可能导致溢出的算术运算的代码时开发人员忽略解释溢出可能性的情况下的错误.(这些语言可能包含类似"未经检查"的关键字,它可以指定允许发生整数溢出而不会引发异常的块,在开发人员明确意图该行为的情况下; C#实际上确实有这个. )
答案简单归结为性能 - 语言设计者不希望他们各自的语言默认具有"慢"算术整数运算,其中运行时需要做额外的工作来检查是否发生溢出,在每个适用的算术上操作 - 这种性能考虑超过了在无意溢出发生时避免"无声"故障的价值?
除了性能考虑之外,还有其他原因可以做出这种语言设计决策吗?
我已经学会了(至少在java中)整数/长值静默地溢出,它们的值从溢出时的最小值开始而不是抛出任何异常.
我正在使用外部api进行某些文件操作,其中从文件属性加载最大文件大小.在我当地的测试环境中一切都很好.代码进入实时环境后,最大文件大小限制根本不起作用.经过两天调试/分析代码后,根本没有成功.然后由于其他原因,我采用了live constants.properties文件并用它调试了代码.O_0
我只想问,是什么阻止他们在溢出时抛出异常?
任何人都可以帮我理解为什么Int类型溢出结果与更高的数字不一致.有时它是正的,有时是负的,最后收敛到零.
import scala.annotation.tailrec
object FactorialExample {
def main(args: Array[String]): Unit = {
(1 to 100).foreach(i => println(s"Factorial of ${i} is " + factorial(i)))
}
def factorial(i: Int): Int = {
@tailrec
def fact(i: Int, acc: Int): Int = {
if (i <= 0) acc
else fact(i - 1, acc * i)
}
fact(i, 1)
}
}
Run Code Online (Sandbox Code Playgroud)