Java乘法运算行为

时间:2009-02-04 17:02:02

标签: java overflow integer-overflow

我写了一个方法将给定数字从天转换为毫秒:

private long expireTimeInMilliseconds;
...
public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = expireTimeInDays * 24 * 60 * 60 * 1000;
}

我很难弄明白我做错了什么。现在我的问题: 这个错误是如此明显吗?

纠正方法:

private long expireTimeInMilliseconds;
...
public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = ((long) expireTimeInDays) * 24 * 60 * 60 * 1000;
}

如果我在计算之前没有将整数转换为long,我会得到一个完全错误的结果。

10 个答案:

答案 0 :(得分:8)

这是显而易见的吗?我想这取决于你使用Java多长时间以及你需要多少次处理毫秒。当然,它应该可以持续大约24天......

我认为最大的提示应该是System.currentTimeMillis()返回long。这是一个很好的迹象,可以在几毫秒内变大。您正在设置的变量类型也应该是一个很好的提示。

当然,你知道如果用int进行算术运算,结果将是int,溢出时会有回绕。这是否足够明显可以辩论,但这将是一个非常毫无意义的讨论。在C#中,如果你打开了溢出检查,你就会很快发现错误 - 但是那时没有多少开发人员这样做(事实上,我不应该这样做)。

答案 1 :(得分:7)

是的,如果你以前做过,那就很明显了。每当你看到一串数字成倍增加时,你应该自动开始考虑整数溢出错误。在这种情况下,如果expireTimeInDays超过24,则设置为溢出。从技术上讲,您应该在任何时候使用整数时考虑溢出错误,但是将它们乘以一组这样应该是一个非常大的红旗。

答案 2 :(得分:3)

您的操作数变量和文字数字的类型为int。 int数据类型的最大值为2 ^ 31 -1。因此,如此大的数字,int的数据类型溢出导致看似错误的答案。

在您的第一个示例中,int仅在分配给变量时提升为 >计算后的变量。计算结果是int。

第二个例子,将第一个操作数强制转换为long,导致计算推广到很长时间。在这种情况下,由于促销,计算结果很长。长数据类型足以进行计算。

答案 3 :(得分:3)

您可能有兴趣知道Joshua Bloch和Neal Gafter的“Java Puzzlers”中有这个内容。

alt text
(来源:javapuzzlers.com

你会在那本书中找到许多其他Java陷阱,陷阱和角落案例。

我同意留下评论的星蓝。在数字上附加一个L.

答案 4 :(得分:2)

不,这不明显。

但请相信我,经过多年的练习和修复这样的错误后,你会对整数溢出变得非常明智,只是在没有考虑它的情况下做正确的事情。

这是发生在每个人身上的事情。肯定没有坏代码练习的迹象,无知等等。

答案 5 :(得分:1)

只是为了添加其他答案,我发现在过去定义常量(public static final long)很有帮助,例如MILLISECS_DAYMILLISECS_HOUR。 更具可读性和实用性。

答案 6 :(得分:1)

另一种写这个的方法是

public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = (long) expireTimeInDays * 24 * 60 * 60 * 1000;
}

public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = expireTimeInDays * 24L * 60 * 60 * 1000;
}

答案 7 :(得分:1)

如果在代码中使用FindBugs,它将检测到这个确切的问题。 “ICAST:整数乘法的结果转为长。” FindBugs的例子就是你正在做的事情;以毫秒计算天数。

第一次遇到这个问题对我来说并不明显。

答案 8 :(得分:1)

有一些静态分析工具(findbugs)可以找到这些类型的错误。

计算机上的数值计算可能很难。操作顺序可能会以您不期望的方式影响精度和准确性。日期数学也可能非常棘手。通常最好使用Date / Calendar例程而不是自己尝试数学,但这些例程不是java类库中最好的例程。

答案 9 :(得分:0)

我并不是要证明我的错误是正确的,但如果java编译器足够聪明以在计算之前将int推广到很长时间(一旦将计算分配给long类型的变量),那就太棒了< / p>

顺便说一下,我曾经使用C / C ++,如果它是一个C程序,我也有同样的问题,但几年前我对这种操作更加小心。

下次我会更加注意(或切换到python)......:D