java - lambda 数组有缺点吗?

原文 标签 java arrays lambda

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

为了能够改变要迭代的函数并了解 lambda,我尝试将函数实现为 BinaryOperator<T> 的数组- 但 javac 提示它不喜欢泛型类型的数组。

所以我创建了自己的非泛型接口(interface)来提供相同的服务,但只针对我的复数类。有用。它允许我更改正在迭代的函数并组合函数。

我已经阅读了几本关于 Java 8 lambda 的电子书并查看了许多教程,但在这些教程中,我都没有找到任何关于将 lambda 放入数组中的示例或引用。所以我想知道,这里是否存在我遗漏的基本设计缺陷或类型安全缺陷?使用 List 会更好吗?而不是数组,所以我可以使用通用接口(interface)?

以下是相关代码:

@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));
}

作为引用,这是我的 Complex 类:
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

最佳答案

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

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

使用 List 没有缺点.通过运行时优化,使用 ArrayList将为您提供与数组相同的性能,甚至链表实现使用迭代器也能很好地执行。鉴于数组的缺点(尽管很小),您为什么不使用 List反而?

关于java - lambda 数组有缺点吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35878712/

相关文章:

android - arraymap 比稀疏数组更好地记住从 JSON 文件中捕获的一些数据?

c++ - 将lambdas传递给std::thread并调用类方法

c# - 重构重复的 Lambda 表达式

java - 数据属性的 OWL 类表达式

java - 字符串压缩到字符ArrayList

java - Lombok 的 @NonNull 或 javax @Nonnull

javascript - JS : Remove Element from an Array based on RegExp

java - 仅获取数组中的名字

java - 生成随机数的更好方法

c# - 为什么我可以声明一个与父作用域中的变量同名的子变量?