【问题标题】:Avoid Instant.toEpochMilli() Arithmetic Overflow避免 Instant.toEpochMilli() 算术溢出
【发布时间】:2017-04-17 22:16:29
【问题描述】:

调用 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 time arithmetic-overflow


    【解决方案1】:

    您可以使用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();
    

    【讨论】:

    • 巧妙的解决方案!它解决了捕获异常的性能问题和我编写的 if 语句容易出错的逻辑。
    【解决方案2】:

    toEpochMilli 会在溢出的情况下抛出异常,因此您可以捕获该异常:

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

    这段代码比问题中写的更简单、更安全。它更安全,因为它不会尝试重新实现toEpochMillis() 内部的边界逻辑。

    抛出和捕获异常可能存在性能问题。这取决于抛出异常的频率。如果大部分时间都抛出异常,那么除非 JVM 可以优化它,否则它的性能会更差。如果很少抛出异常,那么性能会很好。

    JVM 或许能够优化这一点,但也许不行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      相关资源
      最近更新 更多