java long 溢出_关于溢出:Java乘法运算行为
我編寫了一種方法,可以將給定的數(shù)字從幾天轉(zhuǎn)換為毫秒:
private long expireTimeInMilliseconds;
...
public void setExpireTimeInDays(int expireTimeInDays)
{
expireTimeInMilliseconds = expireTimeInDays * 24 * 60 * 60 * 1000;
}
我很難找出我做錯了什么。 現(xiàn)在我的問題是:
那個錯誤是如此明顯嗎?
更正的方法:
private long expireTimeInMilliseconds;
...
public void setExpireTimeInDays(int expireTimeInDays)
{
expireTimeInMilliseconds = ((long) expireTimeInDays) * 24 * 60 * 60 * 1000;
}
如果在計算之前不將整數(shù)轉(zhuǎn)換為很長的時間,則會得到完全錯誤的結(jié)果。
您也可以在常量后面加上L。
人們?yōu)槭裁匆P(guān)閉它? 似乎是一個可以幫助他人的正當(dāng)問題。 如果確切重復(fù),請這樣說。
您還可以聲明常量:long 24L * 60L ...
有趣的話題,但我認(rèn)為這里的實際問題需要更改。"錯誤是否明顯"很容易受到影響。 諸如"為什么即使我的變量為long類型,Java為何也不能將其轉(zhuǎn)換為long?" 似乎是這里實際討論的內(nèi)容。
@Outlaw你是對的:" Java為什么不將其轉(zhuǎn)換為long"在這里比較合適。
明顯嗎?我想這取決于您使用Java已有多長時間,以及必須處理多少次毫秒。當(dāng)然,最多可以保留24天左右...
我認(rèn)為最大的提示應(yīng)該是System.currentTimeMillis()返回long。這很好地表明了毫秒數(shù)可能會變大。您要設(shè)置的變量的類型也應(yīng)該是一個很好的提示。
當(dāng)然,您還必須了解,如果使用int進(jìn)行算術(shù)運算,結(jié)果將是int,并在溢出時進(jìn)行環(huán)繞。是否足夠明顯尚有爭議,但這將是毫無意義的討論。在C#中,如果您打開了溢出檢查功能,您會很快發(fā)現(xiàn)該錯誤-但是沒有那么多開發(fā)人員這樣做(實際上,我可能不會這樣做)。
我期待一個很長的時間,我曾經(jīng)使用過System.currentTimeMillis()。因為那不是一個新代碼,所以我記不起編寫它時的想法(可能是我期望編譯器提供一些魔術(shù))...
...我認(rèn)為,就像您所說的那樣,我最大的錯誤是使用int進(jìn)行算術(shù)運算,而沒有注意int溢出。我忘記了基本概念(實際上我沒有為Java學(xué)習(xí),但我已經(jīng)為C / C ++學(xué)習(xí))
是的,如果您之前已經(jīng)做過,那就很明顯了。每當(dāng)您看到一串?dāng)?shù)字相乘時,都應(yīng)該自動開始考慮整數(shù)溢出錯誤。在這種情況下,如果expireTimeInDays大于24,則設(shè)置為溢出。從技術(shù)上講,您應(yīng)該在處理整數(shù)時隨時考慮溢出錯誤,但是像這樣將它們相乘應(yīng)該是一個很大的危險信號。
您可能想知道Joshua Bloch和Neal Gafter撰寫的" Java Puzzlers"中對此進(jìn)行了介紹。
(來源:javapuzzlers.com) sub>
您將在本書中發(fā)現(xiàn)許多其他的Java陷阱,陷阱和極端案例。
我同意發(fā)表評論的繁星點點。在數(shù)字后面加上L。
您的操作數(shù)變量和文字?jǐn)?shù)字的類型為int。 int數(shù)據(jù)類型的最大值為2 ^ 31 -1。因此,使用如此大的數(shù)字,int的數(shù)據(jù)類型會溢出,從而導(dǎo)致看似錯誤的答案。
在您的第一個示例中,僅將int賦值給在計算后出現(xiàn)的變量上很長的賦值。計算結(jié)果為整數(shù)。
第二個示例將第一個操作數(shù)強(qiáng)制轉(zhuǎn)換為long,導(dǎo)致將計算提升為long。在這種情況下,由于提升,計算的結(jié)果很長。 long數(shù)據(jù)類型足以進(jìn)行計算。
看起來Java具有與C相同的int溢出行為。我想我期望編譯器為我將其轉(zhuǎn)換(int到long)。它的代碼看起來很簡單(就是這樣)...我只需要更加注意。
不,這不是顯而易見的。
但是請相信我,經(jīng)過幾年的實踐并修復(fù)了此類錯誤之后,您對整數(shù)溢出變得非常明智,甚至在做正確的事情時都沒有考慮它。
這件事發(fā)生在每個人身上。絕對沒有不良實踐,無知之類的跡象。
有趣的是,我已經(jīng)編碼了20多年,這是我第一次犯該特定錯誤。當(dāng)我是C / C ++開發(fā)人員時,我曾經(jīng)注意代碼中的每個小細(xì)節(jié)。我認(rèn)為現(xiàn)在我希望編譯器為我做一些"魔術(shù)" ...
有一些靜態(tài)分析工具(findbug)可以找到這些類型的錯誤。
在計算機(jī)上進(jìn)行數(shù)字?jǐn)?shù)學(xué)可能很困難。操作順序問題可能會以您意想不到的方式影響精度和準(zhǔn)確性。日期數(shù)學(xué)也可能非常棘手。通常,使用Date / Calendar例程比嘗試自己做數(shù)學(xué)要好,但是這些例程并不是Java類庫中設(shè)計最好的例程。
如果在代碼上使用FindBugs,它將檢測到此確切問題。" ICAST:整數(shù)乘法的結(jié)果強(qiáng)制轉(zhuǎn)換為long。" FindBugs的示例正是您在做什么;計算天數(shù)(以毫秒為單位)。
第一次遇到這個問題對我來說并不明顯。
另一種寫方法是
public void setExpireTimeInDays(int expireTimeInDays)
{
expireTimeInMilliseconds = (long) expireTimeInDays * 24 * 60 * 60 * 1000;
}
要么
public void setExpireTimeInDays(int expireTimeInDays)
{
expireTimeInMilliseconds = expireTimeInDays * 24L * 60 * 60 * 1000;
}
這樣比較好,我寧愿避免不必要的轉(zhuǎn)換。謝謝
只是為了增加其他答案,我發(fā)現(xiàn)在過去定義常量(public static final long)如MILLISECS_DAY或MILLISECS_HOUR很有幫助。
更具可讀性和實用性。
我并不是想證明我的錯誤,但是如果Java編譯器足夠聰明,可以在計算之前很長一段時間將int提升到很長時間(一旦將計算分配給long類型的變量),那將是很好的選擇
順便說一下,我曾經(jīng)使用過C / C ++,如果它是C程序,我也會遇到同樣的問題,但是幾年前,我對這種操作更加謹(jǐn)慎。
下次我會更加關(guān)注(或切換到python)...:D
總結(jié)
以上是生活随笔為你收集整理的java long 溢出_关于溢出:Java乘法运算行为的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: retrofit 会请求两次_Retro
- 下一篇: java美元兑换,(Java实现) 美元