0二、Java的lambda表達式和JavaScript的箭頭函數

前言

在JDK8和ES6的語言發展中,在Java的lambda表達式和JavaScript的箭頭函數這二者有着千絲萬縷的聯繫;本次試圖經過這篇文章弄懂上面的兩個「語法糖」。javascript

簡介

Lambda 表達式來源於 C# 5.0,但又不太肯定,因而查了下 百度百科:Lambda表達式,仍然沒有獲得明確的答案,因此懶得去糾結這個問題了。html

箭頭函數(arrow function),就是C#中的lambda表達式,聽說Java8也把它加入了。但無論怎樣,JS正在從其它語言吸納優秀的特性(好比yield, class, 默認參數等等),且不論這些特性好壞,這件事自己就是極好的(至少咱們正在使用的是一個充滿活力的工具)java

只是Java用->箭頭,C#用的箭頭與JS同樣:=>,這個箭頭叫「lambda運算符」,行話讀做」goes to」git

lambda表達式(箭頭函數)聽說是定義函數最簡潔的方法,語法上幾乎沒有冗餘成分了。由於JS弱類型的特色,JS中的lambda表達式要比C#和Java中的更簡潔(少了參數類型聲明)github

一句話,箭頭函數就是lambda表達式,提供了更簡潔的function定義方式express

lambda語法

什麼是lambda?

這裏先給簡要的定義:將匿名函數複製給變量的簡寫方式的函數稱爲 lambda 表達式編程

一、java的場景中:把「一塊代碼」賦給一個Java變量ide

java場景

這個是簡化過程:
Java的lambda函數式編程

二、JS中同理也是比較簡單的函數

var fun1 = funcation(int x,int y){
    return (x+y);
}

簡寫以下:

var fun1 = (x,y)=>x+y;

lambda的語法定義

這裏因爲Java一切皆對象的緣由,暫時先介紹JavaScript的定義,但Java基本雷同

JavaScript的箭頭函數

Lambda 表達式的主要形式是以下定義,符號的左側是參數,右側是表達式或語句塊。

(參數列表) => { 語句塊 }

當「語句塊」只有一條語句的時候,能夠省略大括號,就成了

(參數列表) => 語句

注意: Lambda 表達式通常是做爲參數或者值使用,因此根據使用的上下文,大部分狀況下編譯器能夠推斷出 Lambda 表達式的參數類型;Lambda 表達式的參數一般是省略類型的

Java的lambda表達式

Lambda 表達式的做用其實就是匿名方法,而 Java 中並無匿名方法這一語法。不過 Java 中有匿名對象,當你直接 new 一個接口並實現接口方法的時候,Java 編譯器實際是產生了一個類(匿名類)來實現這個接口,而後再返回這個類的一個實例,也就是匿名對象;Lambda表達式自己就是一個接口的實現

Lambda簡寫示意圖

這種只有一個接口函數須要被實現的接口類型,咱們叫它」函數式接口「。爲了不後來的人在這個接口中增長接口函數致使其有多個接口函數須要被實現,變成"非函數接口」,咱們能夠在這個上面加上一個聲明@FunctionalInterface, 這樣別人就沒法在裏面添加新的接口函數了:

Lambda簡寫示意圖

下面是一個完整的案例:

@FunctionalInterface
public interface WorkerInterface {
    public void doSomeWork();
}

public class WorkerInterfaceTest {

    public static void execute(WorkerInterface worker) {
        worker.doSomeWork();
    }

    public static void main(String [] args) {

        //invoke doSomeWork using Annonymous class
        execute(new WorkerInterface() {
            @Override
            public void doSomeWork() {
                System.out.println("Worker invoked using Anonymous class");
            }
        });

        //invoke doSomeWork using Lambda expression
        execute( () -> System.out.println("Worker invoked using Lambda expression") );
    }

}

lambda的常見使用場景

上面經過兩個簡單的案例演示了lambda,如今總結一下在Java和JavaScript常見的用法和使用常見。

java中常見的使用場景

1. 什麼時候用?

JAVA8中就提供了這種「函數式編程」的方法 —— lambda表達式,供咱們來更加簡明扼要的實現內部匿名類的功能。

函數式接口:Functional Interface.
定義的一個接口,接口裏面必須 有且只有一個抽象方法 ,這樣的接口就成爲函數式接口。
在可使用lambda表達式的地方,方法聲明時必須包含一個函數式的接口。

簡單的說,凡是(java8以上)函數式接口均可以儘可能使用lambda表達式,注意:若是咱們提供的這個接口包含一個以上的Abstract Method,那麼使用lambda表達式則會報錯。建議定義的接口加上@FunctionalInterface註解。

2. 怎麼用?

根據以前的思路;只要找到Java中函數式接口的皆能夠放出lambda表達式的大招。

  1. JDK 8以前已有的函數式接口

    java.lang.Runnable
    java.util.concurrent.Callable
    java.security.PrivilegedAction
    java.util.Comparator
    java.io.FileFilter
    java.nio.file.PathMatcher
    java.lang.reflect.InvocationHandler
    java.beans.PropertyChangeListener
    java.awt.event.ActionListener
    javax.swing.event.ChangeListener

  2. Java SE 8中增長了一個新的包:java.util.function,它裏面包含了經常使用的函數式接口:
    JDK經常使用函數式接口

補充: 關於函數式接口的詳細總結

1)Java8中Iterable的foreach(Comsumer action)的函數式接口
image

2)Java8中Iteror的forEachRemaining(Comsumer action)的函數式接口
image

3)Java8中函數式接口Predicate;Collections的removeIf(Predicate filter)
image

...其實還有不少,就不一一列舉了,其實根據規則就很容易了加上編譯器優化,其實寫出lambda其實也是很容易。

JavaScript的箭頭函數經常使用場景:

因爲JavaScript基於函數編程,lambda表達式很是靈活經常使用,基本上對於參數的簡單操做均可以使用箭頭函數完成,這裏能夠告訴你不要試圖濫用。

  • 箭頭函數適合於無複雜邏輯或者無反作用的純函數場景下,例如用在map、reduce、filter的回調函數定義中;
  • 不要在最外層定義箭頭函數,由於在函數內部操做this會很容易污染全局做用域。最起碼在箭頭函數外部包一層普通函數,將this控制在可見的範圍內;
  • 如開頭所述,箭頭函數最吸引人的地方是簡潔。在有多層函數嵌套的狀況下,箭頭函數的簡潔性並無很大的提高,反而影響了函數的做用範圍的識別度,這種狀況不建議使用箭頭函數。

參考資料

相關文章
相關標籤/搜索