从方法返回Double.NaN是一个很好的做法,表示无效的double值

时间:2014-07-10 16:56:15

标签: java

目前,我正在实施一个带有以下签名的方法

public static double Newtons_method(double[] payments, double[] days, double guess)

有时候,计算会失败。有几种方法可以表明失败。

  1. 将返回的类型更改为Double,并返回null。
  2. 引发异常。
  3. 返回Double.NaN并使用Double.isNaN(double)对其进行测试。
  4. 然而,有几个问题。

    1. 出于性能目的,我不想返回Object。如果使用Double,我需要做很多方法和拆箱。
    2. 出于性能目的,我不想抛出异常。此外,try catch会使代码看起来很混乱。不是,在Newtons_method中,有很多常见的情况会导致此类算法失败。因此,将它们视为exception
    3. 可能不合适

      第3种方法怎么样,返回Double.NaN?这是一种好的做法吗?

      以下是供您参考的源代码。

      https://github.com/yccheok/xirr/blob/master/src/org/yccheok/quant/XIRR.java#L56

      请注意,尚未执行任何错误检查。因此,err可能永远不会进一步减少,并且该方法可能会进入无限循环。

3 个答案:

答案 0 :(得分:5)

一般而言,在特殊情况下使用特殊返回值的做法违背了Java的方式,通过Java的方式通知调用者异常情况。为此,策略#1和#3是等效的,因为它们都会产生这样的调用者代码:

// This could be double or Double
double res = Newtons_method(pmt, guess);
// This could be res==null check or Double.isNaN(res) call
if (!checkResult(res)) {
    // Do something else
}
// Do regular processing

这很容易出错,因为不可避免地会有人忘记检查,导致错误发生。当嵌套方法调用时,这往往会发生更多,如

double res = doStuff(Newtons_method(pmt1, guess), Newtons_method(pmt2, guess));

不正确的结果使它成为下一级函数调用的参数,强制参数异常(如果编码器非常善于他的参数检查)或者很难调试错误。

你的策略#2更好,因为来电者不能简单地忘记"捕获异常:他们必须捕获并处理它,或者将throws添加到他们自己的方法中。

答案 1 :(得分:1)

这是一个结合了异常的安全网优势的解决方案,但不会强制调用者使用它们来检查成功或失败。如果调用者不想要这个成本,那么每次结果失败时它也没有抛出异常的成本:

public Result compute(...) { ... }

public interface Result {
    /**
     * Returns true if the computation was successful
     */
    boolean isSuccessFul();

    /**
     * Returns the computed value if successful.
     * @throws IllegalStateException if the computation failed - you could use another exception here if you prefer
     */ 
    double getValue();

    /**
     * Gets the reason for the failure, is the computation has failed.
     * @throws IllegalStateException if the computation succeeded
     */
    String getFailureReason();
}

class Success implements Result {
    private final double value;

    public Success(double value) {
        this.value = value;
    }

    @Override
    public boolean isSuccessFul() {
        return true;
    }

    @Override
    public double getValue() {
        return value;
    }

    @Override
    public String getFailureReason() {
        throw new IllegalStateException("The computation was successful");
    }
}

class Failure implements Result {
    private final String reason;

    public Failure(String reason) {
        this.reason = reason;
    }

    @Override
    public boolean isSuccessFul() {
        return false;
    }

    @Override
    public double getValue() {
        throw new IllegalStateException(reason);
    }

    @Override
    public String getFailureReason() {
        return reason;
    }
}

这样,假设结果成功的调用者将会

double result = compute().getValue();

如果结果失败,将获得有意义的异常。

测试结果的人将能够在没有任何性能损失的情况下执行此操作:

Result r = compute();
if (r.isSuccessful()) {
    double value = r.getValue();
    ...
}
else {
    ...
}

这与返回null基本类似,除了代码更加不言自明,调用者忘记测试失败案例的机会少得多,并且在这种情况下得到一个有意义的异常。

答案 2 :(得分:0)

我看到人们以类似的方式使用Double.NaN,而且我从未听过有人说这样做是不好的做法。您可能希望放入使用该方法的方法Javadoc。