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没有任何缺点。通过运行时优化,使用 ArrayList 将为您提供与数组相同的性能,甚至链表实现使用迭代器也能表现良好。考虑到数组的缺点(尽管很小),为什么不使用 List 来代替呢?

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

相关文章:

java - 更新 Intelij 后在线程 "main"java.lang.NoClassDefFoundError : org/testng/TestNG 中获取异常

java - 比较 2 个数组并删除重复项? java

javascript - 为什么 length 在数组对象中不作为键出现?

c++ - 如何访问 lambda 中的数组成员?

java - 无法从 ArrayList<Object> 转换为 ArrayList<MyObject>

java - 将哈希表保存到文件的最佳方法是什么?

c - 编写一个 C 程序,从附带的数据文件中读取整数,并使用插入排序将排序后的数据存储到数组中

c++ - 为什么不能在没有可变参数的情况下在 lambda 内部转发参数?

amazon-web-services - 主机名/IP 与证书的别名不匹配

java - 保护 Android 中的信息