lambda数组是否存在缺点?

时间:2016-03-08 21:49:45

标签: java arrays lambda

我一直在开发一个程序,它迭代复杂的函数,以生成Mandelbrot和Julia集,以各种方式着色。

为了能够改变要迭代的函数,并了解lambdas,我尝试将函数实现为BinaryOperator<T>的数组 - 但是javac抱怨说它不喜欢数组通用类型。

所以我创建了自己的非通用接口来提供相同的服务,但仅适用于我的复杂数字类。有用。它允许我改变被迭代的函数并组成函数。

我已经阅读了几本关于Java 8 lambdas的电子书并查看了许多教程,但是在这些教程中没有找到任何关于将lambdas放入数组的想法的例子或参考。所以我想知道,我缺少一个基本的设计缺陷或类型安全漏洞吗?使用List代替数组会更好吗,所以我可以使用通用接口吗?

以下是相关代码:

@FunctionalInterface
private interface ComplexFunction {
    Complex apply(Complex z);
}

@FunctionalInterface
private interface BiComplexOperator {

    Complex apply(Complex z, Complex w);

    default BiComplexOperator andThen(ComplexFunction after) {
        Objects.requireNonNull(after);
        return (z, w) -> after.apply(apply(z, w));
    }
    default BiComplexOperator compose(ComplexFunction before) {
        Objects.requireNonNull(before);
        return (z, w) -> apply(before.apply(z), w);
    }

}

private static final BiComplexOperator[] functionToIterate = new BiComplexOperator[] {
  (z, c) -> Complex.sum(z.pow(powerOfZ), c),                                // 0
  (z, c) -> Complex.sum(z.pow(powerOfZ).exp(), c),                          // 1
  (z, c) -> Complex.sum(z.pow(powerOfZ).sqrt(), c),                         // 2
  (z, c) -> Complex.sum(z.sqrt().pow(powerOfZ), c),                         // 3
  (z, c) -> Complex.sum(z.pow(powerOfZ).exp().sqrt(), c),                   // 4
  (z, c) -> Complex.sum(z.pow(powerOfZ).sqrt().exp(), c),                   // 5
  (z, c) -> Complex.sum(z.pow(powerOfZ), new Complex(sin(c.x), cos(c.y))),  // 6
  (z, c) -> Complex.sum(z.pow(powerOfZ), Complex.difference(c, z)),         // 7
  null,
  null
};

static {
    functionToIterate[8] = functionToIterate[0].compose(Complex::recip).andThen(Complex::recip);
    functionToIterate[9] = functionToIterate[0].andThen(Complex::sqrt).compose(z -> new Complex(z.y, -z.x));
}

供参考,这是我的复杂课程:

class Complex {

    public double x, y;
    public static final Complex ZERO = new Complex(0.0, 0.0);
    public static final Complex ONE = new Complex(1.0, 0.0);
    public static final Complex I = new Complex(0.0, 1.0);
    public static final Complex MIN_VALUE = new Complex(Double.MIN_VALUE, 0.0);


    public Complex() {
        this.x = 0.0;
        this.y = 0.0;
    }

    public Complex(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public Complex(Complex z) {
        this.x = z.x;
        this.y = z.y;
    }

    public boolean equals(Complex z) {
        return z == null ? false : this.x == z.x && this.y == z.y;
    }

    public boolean equals(double x) {
        return this.x == x && this.y == 0.0;
    }

    public static Complex sum(Complex z, Complex w) {
        return new Complex(z.x + w.x, z.y + w.y);
    }

    // overloaded for convenience to take 3 arguments...
    public static Complex sum(Complex z, Complex w, Complex v) {
        return sum(sum(z, w), v);
    }

    public static Complex sum(Complex z, double s) {
        return new Complex(z.x + s, z.y);
    }

    public static Complex sum(Complex z, Complex w, double s) {
        return sum(sum(z, w), s);
    }

    public static Complex difference(Complex z, Complex w) {
        return new Complex(z.x - w.x, z.y - w.y);
    }

    public static Complex product(Complex z, Complex w) {
        return new Complex(z.x * w.x - z.y * w.y, z.x * w.y + z.y * w.x);
    }

    // overloaded for convenience to take 3 arguments...
    public static Complex product(Complex z, Complex w, Complex v) {
        return product(product(z, w), v);
    }

    public static Complex product(Complex z, double s) {
        return new Complex(z.x * s, z.y * s);
    }

    public static Complex product(Complex z, Complex w, double s) {
        return product(product(z, w), s);
    }

    public static Complex quotient(Complex z, Complex w) {
        double denom = w.x * w.x + w.y * w.y;
        if (denom == 0.0) {
            //String errorMsg = "2nd argument to Complex.quotient() must not be zero.";
            //throw new IllegalArgumentException(errorMsg);
            denom = Double.MIN_VALUE;
        }
        return new Complex((z.x * w.x + z.y * w.y) / denom, (z.y * w.x - z.x * w.y) / denom);
    }

    public Complex recip() {
        return Complex.quotient(ONE, this);
    }

    public Complex squared() {
        return new Complex(this.x * this.x - this.y * this.y, 2.0 * this.x * this.y);
        //return new Complex(this.x * this.x - this.y * this.y, 1.4142135623730950488016887242097 * this.x * this.y);
    }

    public Complex neg() {
        return new Complex(-this.x, -this.y);
    }

    public Complex bar() {
        return new Complex(this.x, -this.y);
    }

    public double abs() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    public Complex pow(int n) {
        if (n < 0 || n > 8192) {
            String errorMsg = "Argument to Complex.pow(int n) must be positive and <= 8192";
            throw new IllegalArgumentException(errorMsg);
        }
        switch(n) {
            case 0:
                return ONE;
            case 1:
                return this;
            case 2:
                return this.squared();
            case 4:
            case 8:
            case 16:
            case 32:
            case 64:
            case 128:
            case 256:
            case 512:
            case 1024:
            case 2038:
            case 4096:
            case 8192:
                return this.pow(n / 2).squared();
            default:
                // in this linear recursion, when n gets down to the
                // first power of 2 less than it, we jump into the exponential
                // recursive cycle...
                return product(this.pow(n-1), this);
        }
    }

    public Complex exp() {
        return product(new Complex(cos(this.y), sin(this.y)), Math.exp(this.x));
    }

    public Complex sqrt() {
        double rootR = Math.sqrt(this.abs());
        double thetaOver2 = atan2(this.y, this.x) / 2.0;
        return new Complex(rootR * cos(thetaOver2), rootR * sin(thetaOver2));
    }

    public String toString() {
        return "" + this.x + " + " + this.y + "i";
    }

}   // end class Complex

1 个答案:

答案 0 :(得分:2)

您应该使用List,而不是数组。

使用数组的缺点是,为了使编译器能够确保List提供的相同级别的类型安全性,您必须使用您自己的非泛型版本复制核心功能接口。

使用List没有任何缺点。通过运行时优化,使用ArrayList将提供与数组相同的性能,甚至链表实现也可以使用迭代器很好地执行。鉴于阵列的缺点虽然很小,但为什么不使用List