我有一些具有这种一般结构的代码:
interface Func<A> {
double apply(Optional<A> a);
}
class Foo {
public double compute(Func<Double> f) {
// Sometimes amend the function to do something slightly different
Func<Double> g = f;
if (someCondition())
g = oa -> Math.max(0, f.apply(oa));
return g.apply(Optional.of(3.14)) + g.apply(Optional.empty());
}
}
这本身就很有效。现在我想更自由一些,例如,如果有人有一个 Func<Number>
或 Func<Object>
而不是 Func<Double>
他们仍然可以将其传递给 compute
. 先验这应该是足够安全的。很好,所以我将其更改为
public double compute(Func<? super Double> f) {
Func<? super Double> g = f;
if (someCondition())
g = oa -> Math.max(0, f.apply(oa));
...
不幸的是,现在 lambda 不进行类型检查(Eclipse 说),因为 oa
的类型无法传递给 f.apply
.
f
的赋值本身到g
编译器似乎并不担心,如果 apply
的参数不会出现问题是A
而不是 Optional<A>
.
不幸的是,似乎没有办法命名 ? super Double
参数类型,以便我可以再次将其用作 g
的类型和/或用老式的内部类替换 lambda。
例如,这在句法上是不允许的:
public <T super Double> double compute(Func<T> f) {
Func<T> g = f;
...
是否有任何合理优雅的方式来完成这项工作?
到目前为止我想到的最好的是
public double compute(Func<? super Double> f) {
if (someCondition())
return computeInner(oa -> Math.max(0, f.apply(oa)));
else
return computeInner(f);
}
private double computeInner(Func<? super Double> g) {
return g.apply(Optional.of(3.14)) + g.apply(Optional.empty());
}
编译器接受这一点,但除了让类型检查器高兴之外没有其他原因的间接调用并不是我所说的优雅。
最佳答案
试试这个奇怪的技巧:
g = oa -> Math.max(0, f.apply(oa.map(a -> a)));
// ^----------^
像这样映射可选类型允许编译器将可选类型“转换”为一致的类型。
这确实有创建新的 Optional
实例的缺点。
但是,当然,I asked this question考虑这是否实际上是规范允许的事情,还是一个错误。
就我个人而言,我认为您的“迄今为止最好的”并没有特别过分。当然,这取决于真正的代码看起来如何。
关于java - 在不失去通用性的情况下包装逆变函数接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51331635/