我一直在开发一个程序,它迭代复杂函数以生成 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/