假设我们有这样的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();现在假设我们有一个像这样的运行lambda函数:
Function<Object, Function<Object, int[]>> func2 = a->b->new int[2];再说一次,它所做的并不重要。这一次,当前函数接受两个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();现在是第三个变体,我的困惑在哪里,我的问题在哪里。假设我们有这样一个运行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:错误:不兼容类型:对象不能转换为int[] Int[] func3Result3 =Function3.Apply(新的ArrayList()).apply(null);// .apply没有<>就不能工作 /T1459.3-1993技术
为什么它认为返回类型是Object而不是int[]?内部函数的返回类型清楚地表明返回类型是int[]。如果两个lambdas的参数都是Object ( func2测试),或者集合中附加了钻石(func3Result1和func3Result2),那么它就可以正常工作。但是由于某种原因,当钻石从集合(func3Result3)中移除时,它会感到困惑,即使int[]返回类型与这个ArrayList<Integer>输入无关。
编辑:只是在我的jdk版本1.8.0_72上进行了本地测试,并在那里进行了编译和工作。有人能证实它确实不适用于JDK1.9或1.10 (或者JDK1.8的最新版本之一)吗?也许问题是TIO在这里做了一些奇怪的事情,而不是JDK本身。:S
发布于 2018-06-21 08:41:28
总之。当您使用原始类型(如@Holger在注释中提到的你不应该用它们)时,您将删除任何泛型信息。所以这句话:
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);编译器只是不知道类型,因为类型擦除。
所以这件事的寓意是:
不要使用原始类型。它们只是一个向后兼容的特性,不应该在现代生产代码中使用。
https://stackoverflow.com/questions/50962862
复制相似问题