使用 Java 8 Streams 将迭代方法转换为函数式方法

Convert iterative method to functional with Java 8 Streams

我这里有这个算法,

    while ((start + end) / 2 != 0) {
        Double mid = (start + end) / 2;
        if (Math2.pow(mid, 3) < n) {
            start = mid;
        } else if (Math.abs(n - Math2.pow(mid, 3)) > Math2.pow(e, 3)) {
            end = mid;
        } else if (Math.abs(n - Math2.pow(mid, 3)) < Math2.pow(e, 3)) {
            return mid;
        }
    }
    return 0.0;

}

这给了我损失精度为 e 的 n 的立方根。我需要做同样的事情,但使用 Java 8 个流。 Math2 来自私人 git 代表。您可以使用 Math.pow 代替;它也会起作用。如何使用 Streams 执行相同的算法?

Java Stream API 有从 Java 9 开始的方法 Stream::iterate,因此可以实现代表迭代 steps/states 的 class如下:

class CubeSolver {
    static final double EPS = 1E-06;
        
    private double start, end, n, mid;

    public CubeSolver(double s, double e, double n) {
        this.start = s;
        this.end = e;
        this.n = n;
        this.mid = (start + end) / 2;
    }

    // UnaryOperator<CubeSolver> for iteration
    public CubeSolver next() {
        if (done()) {
            return this;
        }
        if (Math.pow(mid, 3) < n) {
            start = mid;
        } else if (Math.abs(n - Math.pow(mid, 3)) > EPS) {
            end = mid;
        }
        return new CubeSolver(start, end, n);
    }
    
    // define end of calculation
    public boolean done() {
        return mid == 0 || Math.abs(n - Math.pow(mid, 3)) < EPS;
    }
    
    @Override
    public String toString() {
        return "root = " + mid;
    }
}

那么基于流的解决方案如下所示:

  1. startendn
  2. 定义初始种子
  3. 使用 Stream::iteratehasNext 谓词创建一个 有限 流 2a) 或使用不带 hasNext 但带有 Stream::takeWhile 操作的旧 Stream::iterate 有条件地限制流 - 自 Java 9
  4. 起也可用
  5. 使用Stream::reduceto get the last element of the stream
CubeSolver seed = new CubeSolver(1.8, 2.8, 8);
CubeSolver solution = Stream
    .iterate(seed, cs -> !cs.done(), CubeSolver::next)
    .reduce((first, last) -> last) // Optional<CubeSolver>
    .orElse(null);
    
System.out.println(solution); 

输出:

root = 2.0000002861022947

在 Java 中添加了 11 static Predicate::not,因此使用 takeWhile 的 2a 解决方案可能如下所示:

CubeSolver seed = new CubeSolver(0, 7, 125);
CubeSolver solution = Stream
    .iterate(seed, CubeSolver::next)
    .takeWhile(Predicate.not(CubeSolver::done))
    .reduce((first, last) -> last) // Optional<CubeSolver>
    .orElse(null);
    
System.out.println(solution); 

输出(对于 EPS = 1E-12):

root = 4.999999999999957