避免 Instant.toEpochMilli() 算术溢出
Avoid Instant.toEpochMilli() Arithmetic Overflow
调用 JDK Instant.toEpochMilli()
可能会导致算术 overflow/underflow(例如 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();
似乎必须有一种 cleaner/clearer 方法来实现它。你会如何实现这个逻辑?
我必须关心 overflow/underflow,因为 Instant.MAX
和 Instant.MIN
被传递给此代码所在的方法。
toEpochMilli
在溢出的情况下抛出异常,因此您可以捕获该异常:
try {
millis = deadline.toEpochMillis();
} catch (AritmeticException ignore) {
millis = deadline.getEpochSecond() < 0 ? Long.MIN_VALUE : Long.MAX_VALUE;
}
这段代码比问题中写的更简单、更安全。它更安全,因为它不会尝试在 toEpochMillis()
.
内重新实现边界逻辑
抛出和捕获异常可能存在性能问题。这取决于抛出异常的频率。如果大多数时候都抛出异常,那么除非 JVM 可以优化它,否则它的性能会更差。如果很少抛出异常,那么性能就可以了。
JVM 可能能够优化它,但也许不能。
您可以使用 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];
}
此方法将 return 一个永远不会在 toEpochMilli()
上溢出的 Instant。
将您的逻辑简化为:
millis = capped(deadline).toEpochMilli();
调用 JDK Instant.toEpochMilli()
可能会导致算术 overflow/underflow(例如 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();
似乎必须有一种 cleaner/clearer 方法来实现它。你会如何实现这个逻辑?
我必须关心 overflow/underflow,因为 Instant.MAX
和 Instant.MIN
被传递给此代码所在的方法。
toEpochMilli
在溢出的情况下抛出异常,因此您可以捕获该异常:
try {
millis = deadline.toEpochMillis();
} catch (AritmeticException ignore) {
millis = deadline.getEpochSecond() < 0 ? Long.MIN_VALUE : Long.MAX_VALUE;
}
这段代码比问题中写的更简单、更安全。它更安全,因为它不会尝试在 toEpochMillis()
.
抛出和捕获异常可能存在性能问题。这取决于抛出异常的频率。如果大多数时候都抛出异常,那么除非 JVM 可以优化它,否则它的性能会更差。如果很少抛出异常,那么性能就可以了。
JVM 可能能够优化它,但也许不能。
您可以使用 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];
}
此方法将 return 一个永远不会在 toEpochMilli()
上溢出的 Instant。
将您的逻辑简化为:
millis = capped(deadline).toEpochMilli();