【问题标题】:Java 8 - Inferring generic return type with lambdasJava 8 - 使用 lambda 推断泛型返回类型
【发布时间】:2015-03-06 11:48:57
【问题描述】:

我试图在 Java 8 中的一些高阶函数中保留来自 lambda 表达式的返回类型的通用类型信息。我已将我的实际代码简化为这个测试用例。问题不在于我期望代码完全执行的操作,而是我期望泛型类型R 被推断为java.lang.String 并通过函数调用进行。

import java.util.function.Function;

public class AdamTest {

    public final static void main(final String args[]) {
        final AdamTest adamTest = new AdamTest();

        final String s = adamTest.thing2(7).apply(i -> i.toString());
        System.out.println(s);
    }


    private <R> R fn1(final Function<Integer, R> op) {
        return op.apply(10);
    }

    private <R> Function<Function<Integer, R>, R> thing2(final Integer val) {
        return fn1(i -> new Function<Function<Integer, R>, R>() {
                @Override
                public R apply(Function<Integer, R> op) {
                    return op.apply(val * i);
                }
            }
        );
    }
}

由于final String s = adamTest.thing2(7).apply(i -&gt; i.toString()); 这一行,目前这段代码无法编译。我认为我的类型界限有些微妙的错误,因为编译器似乎无法推断出thing2(7).apply 的返回类型并报告Object 而不是我希望的String

如何获得正确的泛型类型边界,以便编译器推断正确的返回类型,即java.lang.String

【问题讨论】:

  • 你能添加你得到的错误吗?
  • 编译器从左到右“评估”表达式;问题出现在adamTest.thing2(7)。编译器不会查看 .apply 来确定类型,否则就不可能。
  • 你到底想做什么?这完全不清楚。
  • 感谢@AdrianLeonhard,这是我正在寻找的解释。
  • 你为什么要以这种不一致的方式混合 lambdas 和内部类?为什么不将thing2 实现为return fn1(i -&gt; op -&gt; op.apply(val * i));

标签: java generics lambda java-8


【解决方案1】:

如前所述,这些语句是从左到右计算的。

要强制编译器使用正确的类型,你可以简单的写成

final String s = adamTest.<String>thing2(7).apply(String::valueOf);

编辑:根据 cmets,lambda 表达式可以替换为方法引用(看起来更干净)。

【讨论】:

  • 另外,您可以用方法引用替换对 i.toString() 的方法调用。
  • @MatkoMedenjak 不幸的是,这无法完成。 Integer 类定义了两个名为toString 的方法:一个静态方法Integer.toString(int) 和一个非静态方法Integer.toString()。如果使用方法引用Integer::toString,编译器无法区分它们。
  • 谢谢@Seelenvirtuose 这是我自己想到的解决方案,但不知何故,我真的希望编译器能更好地推断,所以觉得我在泛型中犯了一个错误,这就是我问这个问题的原因.
  • @Seelenvirtuose String::valueOf 另一方面并不模棱两可
  • 如果您对Integer::toString 不明确,请使用Object::toString。方法一样……
【解决方案2】:

我认为没有演员表就无法修复它(也许有人知道得更好)。另一种方法是将您的陈述分成两行:

Function<Function<Integer, String>, String> thing2 = adamTest.thing2(7);
final String s = thing2.apply(i -> i.toString());

还要注意thing2可以简化:

private <R> Function<Function<Integer, R>, R> thing2(final Integer val) {
  return fn1(i -> (op -> op.apply(val * i)));
}

【讨论】:

  • 如果Java 中有auto 类型,我会将其拆分为两个语句,但由于没有,我更喜欢使用@Seelenvirtuose 建议的通用类型转换。不过,我确实喜欢这种简化,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-01
  • 1970-01-01
相关资源
最近更新 更多