我编写了一种方法,可以将给定的数字从几天转换为毫秒:
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;
}
如果在计算之前不将整数转换为很长的时间,则会得到完全错误的结果。
您也可以在常量后面加上L。
人们为什么要关闭它? 似乎是一个可以帮助他人的正当问题。 如果确切重复,请这样说。
您还可以声明常量:long 24L * 60L ...
有趣的话题,但我认为这里的实际问题需要更改。"错误是否明显"很容易受到影响。 诸如"为什么即使我的变量为long类型,Java为何也不能将其转换为long?" 似乎是这里实际讨论的内容。
@Outlaw你是对的:" Java为什么不将其转换为long"在这里比较合适。
明显吗?我想这取决于您使用Java已有多长时间,以及必须处理多少次毫秒。当然,最多可以保留24天左右...
我认为最大的提示应该是System.currentTimeMillis()返回long。这很好地表明了毫秒数可能会变大。您要设置的变量的类型也应该是一个很好的提示。
当然,您还必须了解,如果使用int进行算术运算,结果将是int,并在溢出时进行环绕。是否足够明显尚有争议,但这将是毫无意义的讨论。在C#中,如果您打开了溢出检查功能,您会很快发现该错误-但是没有那么多开发人员这样做(实际上,我可能不会这样做)。
我期待一个很长的时间,我曾经使用过System.currentTimeMillis()。因为那不是一个新代码,所以我记不起编写它时的想法(可能是我期望编译器提供一些魔术)...
...我认为,就像您所说的那样,我最大的错误是使用int进行算术运算,而没有注意int溢出。我忘记了基本概念(实际上我没有为Java学习,但我已经为C / C ++学习)
是的,如果您之前已经做过,那就很明显了。每当您看到一串数字相乘时,都应该自动开始考虑整数溢出错误。在这种情况下,如果expireTimeInDays大于24,则设置为溢出。从技术上讲,您应该在处理整数时随时考虑溢出错误,但是像这样将它们相乘应该是一个很大的危险信号。
您可能想知道Joshua Bloch和Neal Gafter撰写的" Java Puzzlers"中对此进行了介绍。
(来源:javapuzzlers.com) sub>
您将在本书中发现许多其他的Java陷阱,陷阱和极端案例。
我同意发表评论的繁星点点。在数字后面加上L。
您的操作数变量和文字数字的类型为int。 int数据类型的最大值为2 ^ 31 -1。因此,使用如此大的数字,int的数据类型会溢出,从而导致看似错误的答案。
在您的第一个示例中,仅将int赋值给在计算后出现的变量上很长的赋值。计算结果为整数。
第二个示例将第一个操作数强制转换为long,导致将计算提升为long。在这种情况下,由于提升,计算的结果很长。 long数据类型足以进行计算。
看起来Java具有与C相同的int溢出行为。我想我期望编译器为我将其转换(int到long)。它的代码看起来很简单(就是这样)...我只需要更加注意。
不,这不是显而易见的。
但是请相信我,经过几年的实践并修复了此类错误之后,您对整数溢出变得非常明智,甚至在做正确的事情时都没有考虑它。
这件事发生在每个人身上。绝对没有不良实践,无知之类的迹象。
有趣的是,我已经编码了20多年,这是我第一次犯该特定错误。当我是C / C ++开发人员时,我曾经注意代码中的每个小细节。我认为现在我希望编译器为我做一些"魔术" ...
有一些静态分析工具(findbug)可以找到这些类型的错误。
在计算机上进行数字数学可能很困难。操作顺序问题可能会以您意想不到的方式影响精度和准确性。日期数学也可能非常棘手。通常,使用Date / Calendar例程比尝试自己做数学要好,但是这些例程并不是Java类库中设计最好的例程。
如果在代码上使用FindBugs,它将检测到此确切问题。" ICAST:整数乘法的结果强制转换为long。" FindBugs的示例正是您在做什么;计算天数(以毫秒为单位)。
第一次遇到这个问题对我来说并不明显。
另一种写方法是
public void setExpireTimeInDays(int expireTimeInDays)
{
expireTimeInMilliseconds = (long) expireTimeInDays * 24 * 60 * 60 * 1000;
}
要么
public void setExpireTimeInDays(int expireTimeInDays)
{
expireTimeInMilliseconds = expireTimeInDays * 24L * 60 * 60 * 1000;
}
这样比较好,我宁愿避免不必要的转换。谢谢
只是为了增加其他答案,我发现在过去定义常量(public static final long)如MILLISECS_DAY或MILLISECS_HOUR很有帮助。
更具可读性和实用性。
我并不是想证明我的错误,但是如果Java编译器足够聪明,可以在计算之前很长一段时间将int提升到很长时间(一旦将计算分配给long类型的变量),那将是很好的选择
顺便说一下,我曾经使用过C / C ++,如果它是C程序,我也会遇到同样的问题,但是几年前,我对这种操作更加谨慎。
下次我会更加关注(或切换到python)...:D