lambda - Java 8 currying 函数,无法确定 int[] 返回类型

标签 lambda types java-8 currying java-10

假设我们有一个像这样的 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 测试),或者该系列附有钻石(func3Result1func3Result2)。但是由于某种原因,当钻石从收藏中移除时( 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/

相关文章:

c# - 使用 Lambda 表达式验证方法调用 - Moq

c# - 是否可以从 linq 表达式发出和保存 IL 代码?

lambda - 如何在 Java 功能接口(interface)中使用 andThen 或类似方法包装函数

java - 使用 Java 8 流处理嵌套的 if/else 语句

c++ - 在没有 lambda 的情况下将模板化函数作为方法参数传递?

scala - 在没有隐式证据对象的情况下直接使用 Scala 类型类

typescript 语法 : { new (): T } | { new (): T }[]

haskell - Haskell 中的抽象数据类型与参数多态性

Java8 方法引用用作函数对象以组合函数

java - 无法使用季度从 TemporalAccessor 获取 LocalDate