为什么必须为方法引用显式指定类/对象名?
当我想引用当前作用域中的方法时,我仍然需要在::
operator之前指定类名(对于静态方法)。 例如,我需要写:
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()); } }
这不是一个大问题,但有时看起来过于拥挤静态方法,因为类名可能很长。 如果编译器允许我简单地编写::trimmedLength
那将是很好的:
public static void main(String[] args) { System.out.println(Stream.of(" aaa ", " bb ", " c ") .mapToInt(::trimmedLength).sum()); }
但是,Java-8编译器不允许这样做。 对我来说,如果类/对象名称的解析方式与普通方法调用相同,那么它似乎会非常一致。 这也将支持方法引用的静态导入,这在某些情况下也很有用。
所以问题是为什么在Java 8中没有实现这样或类似的语法? 这种语法会出现什么问题吗? 或者根本不考虑它?
我不能代表Java开发人员,但有一些事情需要考虑:
有某种方法参考 :
- 引用静态方法,例如
ContainingClass::staticMethodName
- 引用特定对象的实例方法,例如
containingObject::instanceMethodName
- 引用特定类型的任意对象的实例方法,例如
ContainingType::methodName
- 引用构造函数,例如
ClassName::new
编译器必须做一些工作来消除表单1和3的歧义, 有时它会失败 。 如果允许使用form ::methodName
,则编译器必须消除三种不同forms之间的歧义,因为它可以是从1到3的三种forms中的任何一种。
也就是说,允许form ::methodName
快捷地删除任何forms1到3仍然不会暗示它等同于simpleName ( arg opt )
methodName(…)
forms,因为表达式simpleName ( arg opt )
可能引用
- 当前类或其超类和接口范围内的实例方法
- 当前类或其超类范围内的
static
方法 - 外部类或其超类和接口范围内的实例方法
- 外部类或其超类范围内的
static
方法 - 通过
import static
声明的static
方法
所以说“ ::name
应该被允许引用任何方法name(…)
可以指“暗示结合这两个列表的可能性,你应该在做出愿望之前三思而后行。
作为最后一点,您仍然可以选择编写一个lambda表达式,如args -> name(args)
,这意味着解析name
就像表单name(args)
的简单方法调用一样,同时解决模糊问题,因为它除非你明确写(arg1, otherargs) -> arg1.name(otherargs)
,否则会删除方法引用类的选项3。