我一直在开发一个程序,它迭代复杂的函数,以生成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
答案 0 :(得分:2)
您应该使用List
,而不是数组。
使用数组的缺点是,为了使编译器能够确保List
提供的相同级别的类型安全性,您必须使用您自己的非泛型版本复制核心功能接口。
使用List
没有任何缺点。通过运行时优化,使用ArrayList
将提供与数组相同的性能,甚至链表实现也可以使用迭代器很好地执行。鉴于阵列的缺点虽然很小,但为什么不使用List
?