为什么添加“.map(a -> a)”允许编译?
这与我对“流缩减不兼容类型”的回答有关。我不知道为什么我的建议有效,霍尔格正确地向我施压。但即使是他似乎也没有明确解释为什么它有效。所以,让我们把它当作自己的问题来问:
下面的代码不会编译(对于下面指向 ideone 的链接,这是 http://ideone.com/faq):javac
sun-jdk-1.8.0_51
public <T> Object with(Stream<Predicate<? super T>> predicates) {
return predicates.reduce(Predicate::or);
}
这是正确的:或者将这个流中的两个谓词放在一起就像写作:
Predicate<? super T> a = null;
Predicate<? super T> b = null;
a.or(b); // Compiler error!
但是,它确实在 intellij 中编译,尽管在方法引用上有原始类型警告。显然,它也将在eclipse中编译(根据原始问题)。Predicate::or
但此代码可以:
public <T> Object with(Stream<Predicate<? super T>> predicates) {
return predicates.map(a -> a).reduce(Predicate::or);
// ^----------^ Added
}
尽管我想尝试一下,但我并不完全清楚为什么这会起作用。我的手部波浪式解释是,它的作用类似于“强制转换”,并使类型推断算法具有更大的灵活性,可以选择允许应用的类型。但我不确定那是什么类型。.map(a -> a)
reduce
请注意,这不等同于使用 ,因为它被限制为返回输入类型。ideone demo.map(Function.identity())
任何人都可以解释为什么这与语言规范有关,或者如果像Holger建议的那样,它是一个编译器错误?
更多细节:
方法的返回类型可以更具体一些;我在上面省略了它,以便返回类型上的令人讨厌的泛型不会妨碍:
public <T> Optional<? extends Predicate<? super T>> with(
Stream<Predicate<? super T>> predicates) {
return predicates.map(a -> a).reduce(Predicate::or);
}
这是使用 编译的输出。不完全确定这是否是我可以发布的调试类型推断的最相关的输出;如果有更好的东西,请告知:-XDverboseResolution=all
Interesting.java:5: Note: resolving method <init> in type Object to candidate 0
class Interesting {
^
phase: BASIC
with actuals: no arguments
with type-args: no arguments
candidates:
#0 applicable method found: Object()
Interesting.java:7: Note: resolving method map in type Stream to candidate 0
return predicates.map(a -> a).reduce(Predicate::or);
^
phase: BASIC
with actuals: <none>
with type-args: no arguments
candidates:
#0 applicable method found: <R>map(Function<? super T#1,? extends R>)
(partially instantiated to: (Function<? super Predicate<? super T#2>,? extends Object>)Stream<Object>)
where R,T#1,T#2 are type-variables:
R extends Object declared in method <R>map(Function<? super T#1,? extends R>)
T#1 extends Object declared in interface Stream
T#2 extends Object declared in method <T#2>with(Stream<Predicate<? super T#2>>)
Interesting.java:7: Note: Deferred instantiation of method <R>map(Function<? super T#1,? extends R>)
return predicates.map(a -> a).reduce(Predicate::or);
^
instantiated signature: (Function<? super Predicate<? super T#2>,? extends Predicate<CAP#1>>)Stream<Predicate<CAP#1>>
target-type: <none>
where R,T#1,T#2 are type-variables:
R extends Object declared in method <R>map(Function<? super T#1,? extends R>)
T#1 extends Object declared in interface Stream
T#2 extends Object declared in method <T#2>with(Stream<Predicate<? super T#2>>)
where CAP#1 is a fresh type-variable:
CAP#1 extends Object super: T#2 from capture of ? super T#2
Interesting.java:7: Note: resolving method reduce in type Stream to candidate 1
return predicates.map(a -> a).reduce(Predicate::or);
^
phase: BASIC
with actuals: <none>
with type-args: no arguments
candidates:
#0 not applicable method found: <U>reduce(U,BiFunction<U,? super T,U>,BinaryOperator<U>)
(cannot infer type-variable(s) U
(actual and formal argument lists differ in length))
#1 applicable method found: reduce(BinaryOperator<T>)
#2 not applicable method found: reduce(T,BinaryOperator<T>)
(actual and formal argument lists differ in length)
where U,T are type-variables:
U extends Object declared in method <U>reduce(U,BiFunction<U,? super T,U>,BinaryOperator<U>)
T extends Object declared in interface Stream
Interesting.java:7: Note: resolving method metafactory in type LambdaMetafactory to candidate 0
return predicates.map(a -> a).reduce(Predicate::or);
^
phase: BASIC
with actuals: Lookup,String,MethodType,MethodType,MethodHandle,MethodType
with type-args: no arguments
candidates:
#0 applicable method found: metafactory(Lookup,String,MethodType,MethodType,MethodHandle,MethodType)
Interesting.java:7: Note: resolving method metafactory in type LambdaMetafactory to candidate 0
return predicates.map(a -> a).reduce(Predicate::or);
^
phase: BASIC
with actuals: Lookup,String,MethodType,MethodType,MethodHandle,MethodType
with type-args: no arguments
candidates:
#0 applicable method found: metafactory(Lookup,String,MethodType,MethodType,MethodHandle,MethodType)