为什么必须为方法引用显式指定类/对象名?

时间:2015-05-15 05:06:54

标签: java java-8 method-reference

当我想参考当前范围内的方法时,我仍然需要 在this之前指定类名(对于静态方法)或:: 运营商。例如,我需要写:

import java.util.stream.Stream;

public class StreamTest {
    public static int trimmedLength(String s) {
        return s.trim().length();
    }

    public static void main(String[] args) {
        System.out.println(Stream.of("  aaa  ", "  bb ", " c ")
                .mapToInt(StreamTest::trimmedLength).sum());
    }
}

对于this来说这不是一个大问题,但有时看起来过于拥挤静态方法,因为类名可能很长。如果编译器允许我简单地编写::trimmedLength,那将是很好的:

public static void main(String[] args) {
    System.out.println(Stream.of("  aaa  ", "  bb ", " c ")
            .mapToInt(::trimmedLength).sum());
}

然而,Java-8编译器不允许这样做。对我来说,如果类/对象名称的解析方式与普通方法调用相同,那么它似乎会非常一致。这也可以支持方法引用的静态导入,这在某些情况下也很有用。

所以问题是为什么在Java 8中没有实现这样或类似的语法?这种语法会出现什么问题吗?或者根本不考虑它?

1 个答案:

答案 0 :(得分:6)

我不能代表Java开发人员,但有些事情需要考虑:

有某些kind of method references

  1. 参考静态方法,例如ContainingClass::staticMethodName
  2. 引用特定对象的实例方法,例如containingObject::instanceMethodName
  3. 对特定类型的任意对象的实例方法的引用,例如, ContainingType::methodName
  4. 对构造函数的引用,例如ClassName::new
  5. 编译器必须做一些工作来消除形式1和3以及sometimes it fails的歧义。如果允许使用::methodName形式,则编译器必须消除三种不同形式之间的歧义,因为它可以是从1到3的三种形式中的任何一种。

    也就是说,允许表单::methodName快捷地删除表单1到表单3中的任何表单仍然不会暗示它等同于methodName(…)表单作为表达式simpleName ( argopt )可以参考

    • 当前类或其超类和接口范围内的实例方法
    • 当前类或其超类范围内的static方法
    • 外部类或其超类和接口范围内的实例方法
    • 外部类或其超类范围内的static方法
    • 通过static
    • 声明的import static方法

    所以说“::name之类的内容应该被允许引用任何方法name(…)可能会引用”意味着要结合这两个列表的可能性,你应该在做出愿望之前三思而行。< / p>

    作为最后一点,您仍然可以选择编写像args -> name(args)这样的lambda表达式,这意味着像name一样简单的方法调用同时解析name(args)解决歧义问题,因为它消除了方法引用类型的选项3,除非你明确写出(arg1, otherargs) -> arg1.name(otherargs)