BiConsumer和一个参数的方法参考
BiConsumer and method reference of one parameter
为什么将一个参数的方法引用作为预期类型的参数传递是合法的BiConsumer
,其抽象方法需要两个参数?
示例:
class Experiment {
private String name;
public Experiment(String name) {
this.name = name;
}
public void oneParamMethod(Object o) {
System.out.println(this.name + " and " + o);
}
public <T, S> void executeBiConsumer(BiConsumer<T, S> biCon, T in1, S in2) {
biCon.accept(in1, in2);
}
public static void main(String[] args) {
// notice that the name is "INSTANCE", but it won't be printed out
Experiment exp = new Experiment("INSTANCE");
// executeBiConsumer expects a functional of two params but is given a method
// reference of one param. HOW IS THIS LEGAL?
exp.executeBiConsumer(Experiment::oneParamMethod, new Experiment("PARAM"), 999);
}
}
输出:
PARAM and 999
让我们更改调用,使第二个参数 不是 Experiment
的实例,如下所示:
exp.executeBiConsumer(Experiment::oneParamMethod, new String("INVALID"), 999);
现在,它无法编译。
- 如果第二个参数是
Experiment
实例,为什么代码编译没有报错,否则为什么不编译?
- 为什么将只有一个参数的方法引用作为需要
BiConsumer
的参数传递是有效的?
引用具有一个参数的实例方法的方法引用实际上有两个参数 - 第一个参数是隐式的 - 执行该方法的实例。
Experiment::oneParamMethod
等价于 (Experiment e, Object o) -> e.oneParamMethod(o)
.
您传递给 executeBiConsumer
的 BiConsumer<T, S>
是一个 BiConsumer<Experiment,Object>
,这意味着它必须接收 Experiment
的实例作为 [=18] 的第一个参数=]方法。
因此
exp.executeBiConsumer(Experiment::oneParamMethod, new Experiment("PARAM"), 999);
有效,但是
exp.executeBiConsumer(Experiment::oneParamMethod, new String("INVALID"), 999);
不是。
这是相关的 JLS 参考资料 (15.13.1):
Second, given a targeted function type with n parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form ReferenceType :: [TypeArguments] Identifier, the potentially applicable methods are the member methods of the type to search that have an appropriate name (given by Identifier), accessibility, arity (n or n-1), and type argument arity (derived from [TypeArguments]), as specified in §15.12.2.1.
Two different arities, n and n-1, are considered, to account for the possibility that this form refers to either a static method or an instance method.
您的目标函数类型 - BiConsumer
- 有 2 个参数。因此,可能适用的方法是要搜索的类型 (Experiment
) 的成员方法,它们具有适当的名称 (oneParamMethod
) 和 arity 2 或 1(即 1 或 2 个参数)。这包括您的 public void oneParamMethod(Object o)
方法。
加上
有四种方法引用
- 引用静态方法
- 引用特定对象的实例方法
- 引用特定类型的任意对象的实例方法
- 对构造函数的引用
您使用的属于第三类。如果我们使用 lambda 替换方法引用,我们可以更好地看到这一点。
你正在做的是
BiConsumer<Experiment, Integer> biCon = (experiment, someInt) ->
experiment.oneParamMethod(someInt)
第一个参数成为调用 oneParamMethod
的 object
。与上述等效的方法参考是您使用的 - Experiment::oneParamMethod
.
如果您要将 oneParamMethod
转换为静态,您会得到一个错误,因为 Class::staticMethod
的 lambda 形式会将参数原样传递给静态方法。
看起来像
BiConsumer<Experiment, Integer> biCon = (experiment, someInt) ->
Experiment.oneParamMethod(experiment, someInt)
而且您没有 oneParamMethod
方法接受两个参数。
参考文献:
Ah, I have a problem with the description of the third kind.
这并不像听起来那么复杂。当我们使用stream..filter..map
时,我们大部分时间都使用Class::instanceMethod
。比方说,我们要过滤 Person
年龄超过 18 岁的对象。
persons.stream()
.filter(person -> person.getAge() > 18)
.map(person -> person.getName()) //Get only name
...
这里,person -> person.getName()
可以写成Person::getName
。这与第 3 类情况相同。第一个 implict 参数是 特定类型的任意对象 而 getName
是 实例方法 .
希望这对您有所帮助
为什么将一个参数的方法引用作为预期类型的参数传递是合法的BiConsumer
,其抽象方法需要两个参数?
示例:
class Experiment {
private String name;
public Experiment(String name) {
this.name = name;
}
public void oneParamMethod(Object o) {
System.out.println(this.name + " and " + o);
}
public <T, S> void executeBiConsumer(BiConsumer<T, S> biCon, T in1, S in2) {
biCon.accept(in1, in2);
}
public static void main(String[] args) {
// notice that the name is "INSTANCE", but it won't be printed out
Experiment exp = new Experiment("INSTANCE");
// executeBiConsumer expects a functional of two params but is given a method
// reference of one param. HOW IS THIS LEGAL?
exp.executeBiConsumer(Experiment::oneParamMethod, new Experiment("PARAM"), 999);
}
}
输出:
PARAM and 999
让我们更改调用,使第二个参数 不是 Experiment
的实例,如下所示:
exp.executeBiConsumer(Experiment::oneParamMethod, new String("INVALID"), 999);
现在,它无法编译。
- 如果第二个参数是
Experiment
实例,为什么代码编译没有报错,否则为什么不编译? - 为什么将只有一个参数的方法引用作为需要
BiConsumer
的参数传递是有效的?
引用具有一个参数的实例方法的方法引用实际上有两个参数 - 第一个参数是隐式的 - 执行该方法的实例。
Experiment::oneParamMethod
等价于 (Experiment e, Object o) -> e.oneParamMethod(o)
.
您传递给 executeBiConsumer
的 BiConsumer<T, S>
是一个 BiConsumer<Experiment,Object>
,这意味着它必须接收 Experiment
的实例作为 [=18] 的第一个参数=]方法。
因此
exp.executeBiConsumer(Experiment::oneParamMethod, new Experiment("PARAM"), 999);
有效,但是
exp.executeBiConsumer(Experiment::oneParamMethod, new String("INVALID"), 999);
不是。
这是相关的 JLS 参考资料 (15.13.1):
Second, given a targeted function type with n parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form ReferenceType :: [TypeArguments] Identifier, the potentially applicable methods are the member methods of the type to search that have an appropriate name (given by Identifier), accessibility, arity (n or n-1), and type argument arity (derived from [TypeArguments]), as specified in §15.12.2.1.
Two different arities, n and n-1, are considered, to account for the possibility that this form refers to either a static method or an instance method.
您的目标函数类型 - BiConsumer
- 有 2 个参数。因此,可能适用的方法是要搜索的类型 (Experiment
) 的成员方法,它们具有适当的名称 (oneParamMethod
) 和 arity 2 或 1(即 1 或 2 个参数)。这包括您的 public void oneParamMethod(Object o)
方法。
加上
有四种方法引用
- 引用静态方法
- 引用特定对象的实例方法
- 引用特定类型的任意对象的实例方法
- 对构造函数的引用
您使用的属于第三类。如果我们使用 lambda 替换方法引用,我们可以更好地看到这一点。
你正在做的是
BiConsumer<Experiment, Integer> biCon = (experiment, someInt) ->
experiment.oneParamMethod(someInt)
第一个参数成为调用 oneParamMethod
的 object
。与上述等效的方法参考是您使用的 - Experiment::oneParamMethod
.
如果您要将 oneParamMethod
转换为静态,您会得到一个错误,因为 Class::staticMethod
的 lambda 形式会将参数原样传递给静态方法。
看起来像
BiConsumer<Experiment, Integer> biCon = (experiment, someInt) ->
Experiment.oneParamMethod(experiment, someInt)
而且您没有 oneParamMethod
方法接受两个参数。
参考文献:
Ah, I have a problem with the description of the third kind.
这并不像听起来那么复杂。当我们使用stream..filter..map
时,我们大部分时间都使用Class::instanceMethod
。比方说,我们要过滤 Person
年龄超过 18 岁的对象。
persons.stream()
.filter(person -> person.getAge() > 18)
.map(person -> person.getName()) //Get only name
...
这里,person -> person.getName()
可以写成Person::getName
。这与第 3 类情况相同。第一个 implict 参数是 特定类型的任意对象 而 getName
是 实例方法 .
希望这对您有所帮助