簡體   English   中英

避免Instant.toEpochMilli()算法溢出

[英]Avoid Instant.toEpochMilli() Arithmetic Overflow

調用JDK Instant.toEpochMilli()可能會導致算術上溢/下溢(例如Instant.MAX.toEpochMilli()Instant.MIN.toEpochMilli() )。 我正在尋找一種避免算術溢出的簡單方法,而只需使用Long.MAX_VALUE 這是我當前的代碼。

long seconds, millis;

seconds = deadline.getEpochSecond();

if (seconds > Long.MAX_VALUE / 1000 - 1)
   millis = Long.MAX_VALUE;
else if (seconds < Long.MIN_VALUE / 1000 + 1)
   millis = Long.MIN_VALUE;
else
   millis = deadline.toEpochMilli();

似乎必須有一種更簡潔的方法來實現此目的。 您將如何實現這種邏輯?

我必須擔心上溢/下溢,因為Instant.MAXInstant.MIN傳遞給了此代碼所在的方法。

您可以使用java.lang.Math.addExact 如果發生溢出,它將拋出ArithmeticException 它是在Java 8中添加的。

編輯

好的,再考慮這個問題,我認為我有一個不錯的解決方案:

private Instant capped(Instant instant) {
    Instant[] instants = {Instant.ofEpochMilli(Long.MIN_VALUE), instant, Instant.ofEpochMilli(Long.MAX_VALUE)};
    Arrays.sort(instants);
    return instants[1];
}

此方法將返回一個Instant,它不會在toEpochMilli()上溢出。

將邏輯簡化為:

millis = capped(deadline).toEpochMilli();

如果發生溢出, toEpochMilli會引發異常,因此您可以捕獲該異常:

try {
  millis = deadline.toEpochMillis();
} catch (AritmeticException ignore) {
  millis = deadline.getEpochSecond() < 0 ? Long.MIN_VALUE : Long.MAX_VALUE;
}

此代碼比問題中編寫的代碼更簡單,更安全。 這比較安全,因為它不會嘗試重新實現toEpochMillis()內部的邊界邏輯。

引發和捕獲異常可能存在性能問題。 這取決於引發異常的頻率。 如果大多數時間都拋出異常,那么除非JVM可以對其進行優化,否則這將表現得更糟。 如果很少拋出異常,那么性能會很好。

JVM可能能夠優化這一點,但也許沒有。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM