我了解到方法参考中有4种类型。但我不明白" 参考静态方法 "和" 引用特定类型的任意对象的实例方法 "。
例如:
someList
方法 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);
不一个toUpperCase
方法,为什么他们可以这样写,而不是用这种方式
static
答案 0 :(得分:2)
方法toUpperCase不是静态方法,为什么他们可以用这种方式编写而不是用这种方式
weeks.stream().map(s->s.toUpperCase()).forEach(System.out::println);
方法引用不限到static
方法。看看
.map(String::toUpperCase)
等同于
.map(s -> s.toUpperCase())
Java将只调用您在流中的元素上引用的方法。事实上,这是整个参考点。
官方Oracle tutorial更详细地解释了这一点。
方法Stream#map
(documentation)具有以下签名:
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
所以它期待一些Function
。在您的情况下,这是一个Function<String, String>
,需要String
,在其上应用一些方法,然后返回String
。
现在我们来看看Function
(documentation)。它有以下方法:
R apply(T t)
将此函数应用于给定的参数。
这正是您提供的方法参考。您提供了Function<String, String>
,它将对所有对象应用给定的方法引用。您的apply
看起来像是:
String apply(String t) {
return t.toUpperCase();
}
Lambda表达式
.map(s -> s.toUpperCase())
使用相同的Function
方法生成完全相同的 apply
。
所以你能做的就是
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"));
他们将输出"TEST"
,他们的行为相同。
有关此内容的更多详细信息,请参阅Java语言规范JLS§15.13。特别是看一下本章末尾的例子。
另一个注意事项,为什么Java甚至知道String::toUpperCase
应该被解释为Function<String, String>
?嗯,一般情况下它没有。这就是为什么我们总是需要明确指定类型:
// 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)
另请注意,我们只能使用功能接口:
执行此类操作@FunctionalInterface
public interface Function<T, R> { ... }
System.out::println
出于某种原因,你不会被
弄糊涂.forEach(System.out::println);
此方法也不是 static
。
out
是普通的对象实例,而println
是static
(documentation)类的非PrintStream
方法。有关对象文档,请参阅System#out。
答案 1 :(得分:1)
Java中的方法参考非常智能的特性。所以,当你使用像String:toUpperCase
这样的非静态方法引用时,Java会自动知道它需要在第一个参数上调用toUpperCase
。假设有一个lambda表达式需要的参数然后是方法call
上的first parameter
和second parameter
上的argument
将作为该方法的List<String> empNames = Arrays.asList("Tom","Bob");
String s1 = empNames.stream().reduce("",String::concat); //line -1
String s2 = empNames.stream().reduce("",(a,b)->a.concat(b)); // line -2
System.out.println(s1);
System.out.println(s2);
传递。让我们举个例子。
call
因此,在第-1行的上述示例中,String#concat方法将a
对第一个参数(即b
line-2)和第二个参数(argument
对于第-2行,将作为@IBAction func Save(_ sender: UIButton){
let sterlingpound = sterlingpound.text
let euro = euro.text
let currencyarray = [sterlingpound, euro]
UserDefaults.standard.set(currencyarray, forKey: "DataKey"
UserDefaults.standard.synchronize()
}
传递。
多个参数(超过2个)方法也可能,但您需要非常小心参数的哪个序列。
答案 2 :(得分:0)
我强烈建议您阅读Oracle关于方法引用的文章:https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
这是lambda表达式的形式:
s->s.toUpperCase()
这是方法参考:
String::toUpperCase
从语义上讲,方法引用与lambda表达式相同,它只是具有不同的语法。