java long 溢出_关于溢出:Java乘法运算行为

我编写了一种方法,可以将给定的数字从几天转换为毫秒:

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"中对此进行了介绍。

d46c3dcf23e97ec76a2984836c2d4333.png

(来源: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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值