与lambda的方法参考差异 [英] Method reference difference to lambda
问题描述
我了解到方法参考中有4种类型.但是我不理解" 引用静态方法 "和" 引用特定对象的实例方法"之间的区别输入 ".
例如:
列表< String>周=新的ArrayList<>();week.add("Monday");week.add(星期二");week.add("Wednesday");week.add(星期四");week.add(星期五");week.add("Saturday");week.add("Sunday");week.stream().map(String :: toUpperCase).forEach(System.out :: println);
toUpperCase
方法不是不是静态方法,为什么他们可以这种方式而不是这种方式编写
week.stream().map(s-> s.toUpperCase()).forEach(System.out :: println);
说明
toUpperCase方法不是一个静态方法,为什么他们可以这种方式而不是这种方式编写
weeks.stream().map(s-> s.toUpperCase()).forEach(System.out :: println);
方法引用不限于仅限于 static
方法.看看
.map(String :: toUpperCase)
它等效于
.map(s-> s.toUpperCase())
Java只会调用您在流中的元素上引用的方法.实际上,这就是参考的全部内容.
官方 Oracle教程对此进行了详细说明
见解,范例
Stream#map
方法(文档).它具有以下方法:
R apply(T t)
将此函数应用于给定参数.
这正是您所提供的方法参考.您提供了一个 Function< String,String>
,它将给定的方法引用应用于所有对象.您的应用
如下所示:
字符串apply(String t){返回t.toUpperCase();}
还有Lambda表达式
.map(s-> s.toUpperCase())
使用相同的 apply
方法生成完全相同的 Function
.
所以你可以做的是
Function< String,String>toUpper1 =字符串:: toUpperCase;函数<字符串,字符串>toUpper2 = s->s.toUpperCase();System.out.println(toUpper1.apply("test")));System.out.println(toUpper2.apply("test")));
并且它们都将输出"TEST"
,它们的行为相同.
有关此问题的更多详细信息,请参见Java语言规范JLS§15.13.尤其要看一看本章结尾的例子.
另一个说明,为什么Java甚至不知道 String :: toUpperCase
应该解释为 Function< String,String>
?好吧,总的来说不是.因此,我们始终需要明确指定类型:
//语句的左侧使编译器很清楚函数<字符串,字符串>toUpper1 =字符串:: toUpperCase;//'map'方法的签名使编译器很清楚.map(String :: toUpperCase)
还请注意,我们只能使用功能界面:
@FunctionalInterface公共接口功能< T,R>{...}
关于 System.out :: println
的说明由于某些原因,您不会感到困惑
.forEach(System.out :: println);
此方法也不 静态
.
out
是一个普通的对象实例,而 println
是 PrintStream
的非 static
方法(文档)类.请参阅 System#out 对象文档.
I've learned that there are 4 kinds of types in method reference. But I don't understand the difference between "Reference to a static method" and "Reference to an instance method of an arbitrary object of a particular type".
For example:
List<String> weeks = new ArrayList<>();
weeks.add("Monday");
weeks.add("Tuesday");
weeks.add("Wednesday");
weeks.add("Thursday");
weeks.add("Friday");
weeks.add("Saturday");
weeks.add("Sunday");
weeks.stream().map(String::toUpperCase).forEach(System.out::println);
The method toUpperCase
is not a static
method why they can write in this way rather than using this way
weeks.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
Explanation
The method toUpperCase is not a static method why they can write in this way rather than using this way
weeks.stream().map(s->s.toUpperCase()).forEach(System.out::println);
Method references are not limited to static
methods. Take a look at
.map(String::toUpperCase)
it is equivalent to
.map(s -> s.toUpperCase())
Java will just call the method you have referenced on the elements in the stream. In fact, this is the whole point of references.
The official Oracle tutorial explains this in more detail.
Insights, Examples
The method Stream#map
(documentation) has the following signature:
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
So it expects some Function
. In your case this is a Function<String, String>
which takes a String
, applies some method on it and then returns a String
.
Now we take a look at Function
(documentation). It has the following method:
R apply(T t)
Applies this function to the given argument.
This is exactly what you are providing with your method reference. You provide a Function<String, String>
that applies the given method reference on all objects. Your apply
would look like:
String apply(String t) {
return t.toUpperCase();
}
And the Lambda expression
.map(s -> s.toUpperCase())
generates the exact same Function
with the same apply
method.
So what you could do is
Function<String, String> toUpper1 = String::toUpperCase;
Function<String, String> toUpper2 = s -> s.toUpperCase();
System.out.println(toUpper1.apply("test"));
System.out.println(toUpper2.apply("test"));
And they will both output "TEST"
, they behave the same.
More details on this can be found in the Java Language Specification JLS§15.13. Especially take a look at the examples in the end of the chapter.
Another note, why does Java even know that String::toUpperCase
should be interpreted as Function<String, String>
? Well, in general it does not. That's why we always need to clearly specify the type:
// The left side of the statement makes it clear to the compiler
Function<String, String> toUpper1 = String::toUpperCase;
// The signature of the 'map' method makes it clear to the compiler
.map(String::toUpperCase)
Also note that we can only do such stuff with functional interfaces:
@FunctionalInterface
public interface Function<T, R> { ... }
Note on System.out::println
For some reason you are not confused by
.forEach(System.out::println);
This method is not static
either.
The out
is an ordinary object instance and the println
is a non static
method of the PrintStream
(documentation) class. See System#out for the objects documentation.
这篇关于与lambda的方法参考差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!