gb9*_*b96 2 java generics java-8
在下面的Java 8代码示例中,所有方法都是等效的,除了foo3()之外的所有方法都是编译的.
我怀疑这里涉及的Java编译时泛型有一些更好的点,但它们对我来说似乎并不清楚,而且远非显而易见.
import java.util.function.Function;
public class LambdaTest<T> {
public T foo1(T t) {
Function<T, T> myIdentity = r -> r;
return myIdentity.apply(t);
}
public T foo2(T t) {
Function<T, T> identity = Function.identity();
return identity.apply(t);
}
public T foo3(T t) {
/* XXX Compile error!
* java.lang.Error: Unresolved compilation problem:
* Type mismatch: cannot convert from Object to T
*/
return Function.identity().apply(t);
}
@SuppressWarnings("unchecked")
public T foo4(T t) {
// unchecked conversion from Function<Object, Object> to Function<T, T>
return ((Function<T, T>) Function.identity()).apply(t);
}
public T foo5(T t) {
// provide an explicit type hint to the compiler
return Function.<T>identity().apply(t);
}
public static void main(String[] args) {
String hello = "Hello world!";
LambdaTest<String> test = new LambdaTest<>();
System.out.println("1. " + test.foo1(hello));
System.out.println("2. " + test.foo2(hello));
System.out.println("3. " + test.foo3(hello));
System.out.println("4. " + test.foo4(hello));
System.out.println("5. " + test.foo5(hello));
}
}
Run Code Online (Sandbox Code Playgroud)
foo3()
不起作用,因为它没有给出一个类型来计算它.
Collections.emptyList()和没有lambdas的代码会出现类似的问题:
public void bar1()
{
//Works
List<String> list = Collections.emptyList();
String s = list.get(0);
}
public void bar2()
{
//Compile error
String s = Collections.emptyList().get(0);
}
public void bar3()
{
//Works
String s = Collections.<String>emptyList().get(0);
}
Run Code Online (Sandbox Code Playgroud)
泛型类型推断的Java教程很好地描述了规则 - "目标类型"部分最相关.
在bar1()和bar3()中,编译器可以emptyList()
从返回值推断出泛型参数.这适用于Java 5以上版本.
从Java 8开始,也可以从方法参数推断泛型类型.所以下面的代码:
public void bar4()
{
String s = readFirstElement(Collections.emptyList());
}
private <T> T readFirstElement(List<T> list)
{
return list.get(0);
}
Run Code Online (Sandbox Code Playgroud)
将在Java 8中正常编译,但在早期版本中失败.
但编译器不会从链式方法调用中推断出通用参数,这就是为什么需要像foo5()那样为编译器提供类型参数的显式"提示".