方法参考与lambda的区别

时间:2018-03-18 14:50:55

标签: java lambda method-reference

我了解到方法参考中有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

3 个答案:

答案 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#mapdocumentation)具有以下签名:

<R> Stream<R> map​(Function<? super T, ? extends R> mapper)

所以它期待一些Function。在您的情况下,这是一个Function<String, String>,需要String,在其上应用一些方法,然后返回String

现在我们来看看Functiondocumentation)。它有以下方法:

  

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是普通的对象实例,而printlnstaticdocumentation)类的非PrintStream方法。有关对象文档,请参阅System#out

答案 1 :(得分:1)

Java中的方法参考非常智能的特性。所以,当你使用像String:toUpperCase这样的非静态方法引用时,Java会自动知道它需要在第一个参数上调用toUpperCase。假设有一个lambda表达式需要的参数然后是方法call上的first parametersecond 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表达式相同,它只是具有不同的语法。