假设我们有一个像这样的 lambda 函数:
Function<ArrayList<Integer>, int[]> func1 = a->new int[2];
它做了什么并不重要。重要的是:输入是
ArrayList<Integer>
,输出为 int[]
.使用一些基本的测试编译和运行没有问题:
int[] func1Result1 = func1.apply(new ArrayList<Integer>()); // Non-currying works with <Integer>
System.out.println(func1Result1);
System.out.println(func1Result1.getClass());
System.out.println(Arrays.toString(func1Result1));
System.out.println();
int[] func1Result2 = func1.apply(new ArrayList<>()); // Non-currying works with <>
System.out.println(func1Result2);
System.out.println(func1Result2.getClass());
System.out.println(Arrays.toString(func1Result2));
System.out.println();
int[] func1Result3 = func1.apply(new ArrayList()); // Non-currying works without <>
System.out.println(func1Result3);
System.out.println(func1Result3.getClass());
System.out.println(Arrays.toString(func1Result3));
System.out.println();
Try it online.
现在假设我们有一个像这样的柯里化(Currying) lambda 函数:
Function<Object, Function<Object, int[]>> func2 = a->b->new int[2];
同样,它的作用并不重要。这次柯里化(Currying)函数需要两个
Object
参数,并且仍然输出 int[]
.使用相同的基本测试编译并再次运行没有问题:
int[] func2Result1 = func2.apply(new ArrayList<Integer>()).apply(null); // Currying works with <Integer>
System.out.println(func2Result1);
System.out.println(func2Result1.getClass());
System.out.println(Arrays.toString(func2Result1));
System.out.println();
int[] func2Result2 = func2.apply(new ArrayList<>()).apply(null); // Currying works with <>
System.out.println(func2Result2);
System.out.println(func2Result2.getClass());
System.out.println(Arrays.toString(func2Result2));
System.out.println();
int[] func2Result3 = func2.apply(new ArrayList()).apply(null); // Currying works without <>
System.out.println(func2Result3);
System.out.println(func2Result3.getClass());
System.out.println(Arrays.toString(func2Result3));
System.out.println();
Try it online.
现在是第三个变体,这是我的困惑所在,也是我的问题所在。假设我们有一个像这样的柯里化(Currying) lambda 函数:
Function<ArrayList<Integer>, Function<Object, int[]>> func3 = a->b->new int[2];
这次的参数是
ArrayList<Integer>
和 Object
,并且返回类型仍然是 int[]
.这次使用相同的基本测试将无法编译,并给出错误:
int[] func3Result1 = func3.apply(new ArrayList<Integer>()).apply(null); // Currying works with <Integer>
System.out.println(func3Result1);
System.out.println(func3Result1.getClass());
System.out.println(Arrays.toString(func3Result1));
System.out.println();
int[] func3Result2 = func3.apply(new ArrayList<>()).apply(null); // Currying works with <>
System.out.println(func3Result2);
System.out.println(func3Result2.getClass());
System.out.println(Arrays.toString(func3Result2));
System.out.println();
int[] func3Result3 = func3.apply(new ArrayList()).apply(null); // Currying doesn't work without <>
System.out.println(func3Result3);
System.out.println(func3Result3.getClass());
System.out.println(Arrays.toString(func3Result3));
System.out.println();
错误是:
Main.java:23: error: incompatible types: Object cannot be converted to int[]
int[] func3Result3 = func3.apply(new ArrayList()).apply(null); // Currying doesn't work without <>
^
Try it online.
为什么它认为返回类型是
Object
而不是 int[]
?内部函数的返回类型明确指出返回类型是 int[]
.如果两个 lambda 的参数都是 Object
,它确实可以正常工作。 (func2
测试),或者该系列附有钻石(func3Result1
和 func3Result2
)。但是由于某种原因,当钻石从收藏中移除时( func3Result3
)它会感到困惑,即使 int[]
return-type 与此无关ArrayList<Integer>
输入。编辑:刚刚在我的 jdk 版本 1.8.0_72 上对其进行了本地测试,它确实可以编译和工作。有人可以确认它确实不适用于 jdk 1.9 或 1.10(或最新版本的 jdk 1.8 之一)吗?也许问题是 TIO 在这里做了一些奇怪的事情而不是 JDK 本身.. :S
最佳答案
简而言之。当您使用原始类型(@Holger 在评论中提到的 you should not use them)时,您会删除任何通用信息。所以这一行:
int[] func3Result3 = func3.apply(new ArrayList()).apply(null);
可以拆分为多行以进行澄清:
Function temp = func3.apply(new ArrayList());
在这里,只有
Function
返回,因为使用原始类型 new ArrayList()
删除了通用信息.和原始类型函数有些相似,但不等于
Function<Object, Object>
这使得现在在应用
null
时很容易看到对于该函数,您并不确切知道返回的内容(除了它是 Object
),这就是您收到该错误的原因:int[] func3Result3 = temp.apply(null);
由于类型删除,编译器只是不知道类型。
所以这句话的寓意是:
Never use raw types. They are just a backward compatibility feature which should never be used in modern production code.
关于lambda - Java 8 currying 函数,无法确定 int[] 返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50962862/