为什么要编译这个Java8方法引用?
我目前正在深入研究为什么要编译这个Java8方法引用?,java,java-8,method-reference,Java,Java 8,Method Reference,我目前正在深入研究Java8特性,如Lambdas和方法引用。玩了一会儿,我想到了以下示例: public class ConsumerTest { private static final String[] NAMES = {"Tony", "Bruce", "Steve", "Thor"}; public static void main(String[] args) { Arrays.asList(NAMES).forEach(Objects::requireNo
Java8
特性,如Lambdas和方法引用。玩了一会儿,我想到了以下示例:
public class ConsumerTest {
private static final String[] NAMES = {"Tony", "Bruce", "Steve", "Thor"};
public static void main(String[] args) {
Arrays.asList(NAMES).forEach(Objects::requireNonNull);
}
}
Map<String, String> map = new HashMap<>();
map.put("1", "a");
map.put("1", "A"); // Who cares about the returned value "a"?
我的问题是:
为什么主方法中的行要编译
如果我理解正确,那么引用方法的签名必须与函数接口的SAM签名相对应。在这种情况下,消费者需要以下签名:
void accept(T t);
但是,requirennoull
方法返回T
,而不是void:
public static <T> T requireNonNull(T obj)
public static T requirennull(T obj)
Java语言规范第8版规定:
如果T是函数接口类型(),并且表达式与从T派生的基本目标类型的函数类型一致,则方法引用表达式在赋值上下文、调用上下文或转换上下文中与目标类型T兼容
[……]
如果以下两项均为真,则方法引用表达式与函数类型一致:
- 函数类型标识与引用对应的单个编译时声明
- 以下情况之一是正确的:
- 函数类型的结果无效。
- 函数类型的结果是R,将捕获转换()应用于所选编译时声明的调用类型()的返回类型的结果是R'(其中R是可用于推断R的目标类型),R和R'都不是空的,并且R'在赋值上下文中与R兼容
return
等))
还说:
为了确定编译时结果,如果调用方法的结果为void,则方法调用表达式是表达式语句;如果调用方法的结果为non void,则返回语句的表达式
当方法引用的编译时声明是签名多态性时,此确定的效果是:
- 方法调用的参数类型是相应参数的类型
- 方法调用为void或具有返回类型的Object,这取决于包含方法调用的调用方法是void还是具有返回类型
因此,生成的方法调用将是无效的,以匹配函数类型。除了@Mark Rotterveel的确切答案中所述的内容外,它是编译的,因为在Java中,您可以忽略任何方法调用的结果,如以下示例中所示:
public class ConsumerTest {
private static final String[] NAMES = {"Tony", "Bruce", "Steve", "Thor"};
public static void main(String[] args) {
Arrays.asList(NAMES).forEach(Objects::requireNonNull);
}
}
Map<String, String> map = new HashMap<>();
map.put("1", "a");
map.put("1", "A"); // Who cares about the returned value "a"?
Map Map=newhashmap();
地图放置(“1”、“a”);
地图。放置(“1”、“A”);//谁在乎返回值“a”?
由于在forEach()
consumer块中没有返回任何内容,因此根据规范,它是有效的。考虑myList.forEach(myOtherList::add)
。您是否关心列表。add
返回始终为true的布尔值?如果myOtherList::add
不起作用,那将是一种痛苦。