提问者:小点点

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


当我想引用当前作用域中的方法时,我仍然需要在::运算符之前指定类名(对于静态方法)或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来说,问题并不大,但是对于静态方法来说,有时看起来过于拥挤,因为类名可能很长。如果编译器允许我简单地编写::trimmedLely,那就太好了:

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

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

所以问题是为什么在Java8中没有实现这样或类似的语法?这样的语法会出现任何问题吗?或者根本没有考虑到这一点?


共1个答案

匿名用户

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

有某些类型的方法引用:

  1. 对静态方法的引用,例如ContainingClass::stticControlodName
  2. 引用特定对象的实例方法,例如包含Object::instanceControlodName
  3. 引用特定类型的任意对象的实例方法,例如ContainingType::方法名
  4. 对构造函数的引用,例如ClassHane::new

编译器已经做了一些工作来消除表单1和3的歧义,有时会失败。如果允许表单::方法名称,编译器必须消除三种不同表单之间的歧义,因为它可能是从1到3的三种表单中的任何一种。

也就是说,允许形式::方法名缩短任何形式1到3仍然不意味着它等效于表达式simpleName(argselect可能引用的形式方法名(…)

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

所以说像::name应该被允许引用name(…)可能引用的任何方法意味着将这两个列表的可能性结合起来,你应该在许愿前三思而后行。

最后,您仍然可以选择编写lambda表达式,例如args-