8

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

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,我会得到一个完全错误的结果。

4

10 回答 10

8

很明显吗?我想这取决于您使用 Java 的时间以及您必须处理毫秒的次数。当然,最多24天应该没问题...

我认为最大的提示应该是System.currentTimeMillis()返回一个long. 这是一个很好的迹象,表明毫秒数可能会变大。您设置的变量类型也应该是一个很好的提示。

当然,您必须知道,如果您对整数进行算术运算,结果将是int溢出时回绕。这是否足够明显可以辩论,但这将是一个毫无意义的讨论。在 C# 中,如果您打开溢出检查,您会很快发现错误 - 但没有多少开发人员这样做(确实,我不这样做,尽管我可能应该这样做)。

于 2009-02-04T17:14:06.730 回答
7

是的,如果你以前做过,那就很明显了。每当您看到一串数字相乘时,您应该自动开始考虑整数溢出错误。在这种情况下,如果expireTimeInDays大于 24,您将设置为溢出。从技术上讲,您应该在使用 integers 时考虑溢出错误,但是像这样将一组它们相乘应该是一个非常大的危险信号。

于 2009-02-04T17:14:53.827 回答
3

您的操作数变量和文字数字是 int 类型。int 数据类型的最大值为 2^31 -1。因此,对于如此大的数字,int 的数据类型会溢出,导致看起来不正确的答案。

在您的第一个示例中, int 仅提升为对计算后发生的变量的 long 赋值。计算结果是一个int。

第二个示例将第一个操作数强制转换为 long,从而将计算提升为 long。在这种情况下,由于提升,计算的结果很长。long 数据类型对于您的计算来说已经足够大了。

于 2009-02-04T17:17:50.093 回答
3

您可能有兴趣知道这在 Joshua Bloch 和 Neal Gafter 的“Java Puzzlers”中有所介绍。

替代文字
(来源:javapuzzlers.com

在这本书中,您会发现许多其他 Java 陷阱、陷阱和极端案例。

我同意留下评论的starblue。将 L 附加到数字。

于 2009-02-04T17:30:55.030 回答
2

不,这并不明显。

但是相信我,经过几年的实践和修复这样的错误,你对整数溢出变得非常敏感,并且做正确的事情甚至不考虑它。

这是发生在每个人身上的事情。绝对没有不良代码实践,无知等迹象。

于 2009-02-04T17:13:17.310 回答
1

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

于 2009-02-04T18:33:43.107 回答
1

另一种写法是

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

或者

public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = expireTimeInDays * 24L * 60 * 60 * 1000;
}
于 2009-02-05T02:39:04.360 回答
1

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

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

于 2009-02-05T02:47:55.327 回答
1

有一些静态分析工具(findbugs)会发现这些类型的错误。

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

于 2009-02-05T03:05:25.307 回答
0

我并不是要为我的错误辩护,但是如果 java 编译器足够聪明,可以在计算之前将 int 提升为 long(一旦将计算分配给 long 类型的变量),那就太好了

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

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

于 2009-02-04T20:10:07.093 回答