避免Instant.toEpochMilli()算术溢出

时间:2017-04-17 22:16:30

标签: java time 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会传递给此代码所在的方法。

2 个答案:

答案 0 :(得分:3)

您可以使用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];
}

此方法将返回一个永远不会在toEpochMilli()上溢出的Instant。

简化您的逻辑:

millis = capped(deadline).toEpochMilli();

答案 1 :(得分:1)

如果出现溢出,

toEpochMilli会抛出异常,因此您可以捕获该异常:

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

此代码比问题中的代码更简单,更安全。它更安全,因为它没有尝试重新实现toEpochMillis()内的边界逻辑。

抛出和捕获异常可能存在性能问题。这取决于抛出异常的频率。如果在大多数情况下抛出异常,那么除非JVM能够优化它,否则这将会更糟。如果很少抛出异常,那么性能就会很好。

JVM可能能够优化它,但可能不会。