Java8被稱做Java史上變化最大的一個版本。其中包含不少重要的新特性,最核心的就是增長了Lambda表達式和Stream API。這二者也能夠結合在一塊兒使用。首先來看下什麼是Lambda表達式。
Lambda表達式,維基百科上的解釋是一種用於表示匿名函數和閉包的運算符,感受看到這個解釋仍是以爲很抽象,接下來咱們看一個例子java
public class SwingTest { public static void main(String[] args) { JFrame jFrame = new JFrame("My JFrame"); JButton jButton = new JButton("My JButton"); jButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button Pressed!"); } }); jFrame.add(jButton); jFrame.pack(); jFrame.setVisible(true); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
這是一段Swing編程中的代碼,給Button綁定一個監聽事件,當點擊Button時會在控制檯輸出"Button Pressed!"內容。這裏使用了建立了一個匿名內部類的實例來綁定到監聽器,這也是以往比較常規的代碼組織形式。可是仔細看一下咱們會發現,實際上咱們真正關注的就是一個ActionEvent類型的參數e和向控制檯輸出的語句System.out.println("Button Pressed!");。
若是將上段程序中以匿名內部類的方式建立接口實例的代碼替換成Lambda表達式後,代碼以下
public class SwingTest {編程
public static void main(String[] args) { JFrame jFrame = new JFrame("My JFrame"); JButton jButton = new JButton("My JButton"); jButton.addActionListener(e -> System.out.println("Button Pressed!")); jFrame.add(jButton); jFrame.pack(); jFrame.setVisible(true); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
}
關注最中間部分代碼的變化,由原來的6行代碼,如今1行就能夠實現了。這就是Lambda表達式的一種簡單形式。
能夠看出Lambda表達式的語法是
(param1,param2,param3) -> {segmentfault
//todo
}
這裏參數的類型程序能夠根據上下文進行推斷,可是並非全部的類型均可以推斷出來,此時就須要咱們顯示的聲明參數類型,當只有一個參數時小括號能夠省略。當todo部分只有一行代碼時,外邊的大括號能夠省略。如咱們上面的示例
那麼除了代碼簡潔了,Lambda表達式還給咱們帶來了什麼變化嗎?
咱們回憶一下,在Java中,咱們是否沒法將函數做爲參數傳遞給一個方法,也沒法聲明返回值是一個函數的方法。在Java8以前,答案是確定的。
那麼,在上面的例子中咱們竟然能夠將一段代碼邏輯做爲參數傳遞給了監聽器,告訴監聽器事件觸發時你能夠這麼作,而再也不須要以匿名內部類的方式做爲參數。這也是Java8帶來的另外一新特性:函數式編程。
支持函數式編程的語言有不少,在JavaScript中,把函數做爲參數傳遞,或者返回值是一個函數的狀況很是常見,JavaScript是一門很是常見的函數式語言。
Lambda爲Java添加了缺失的函數式編程的特性,使咱們能將函數當作一等公民看待。
在函數式編程語言中,Lambda表達式的類型是函數。而在Java中,Lambda表達式是對象,它們必須依附於一類特別的對象類型——函數式接口(Functional Interface)。
接下來咱們看下函數式接口的定義:
若是一個接口中,有且只有一個抽象的方法(Object類中的方法不包括在內),那這個接口就能夠被看作是函數式接口。閉包
@FunctionalInterface public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
來看下Runnable接口的聲明,在Java8後,Runnable接口多了一個FunctionalInterface註解,表示該接口是一個函數式接口。可是若是咱們不添加FunctionalInterface註解的話,若是接口中有且只有一個抽象方法時,編譯器也會把該接口當作函數式接口看待。編程語言
@FunctionalInterface public interface MyInterface { void test(); String toString(); }
MyInterface這也是一個函數式接口,由於toString()是Object類中的方法,只是在這裏進行了複寫,不會增長接口中抽象方法的數量。
(到這裏額外提一下,Java8中,接口裏面的方法不單單隻能有抽象方法,也能夠有具體實現了的方法,被稱做默認方法(default method),這部分後面會具體介紹)
既然在Java中,Lambda表達式是對象。那麼這個對象的類型是什麼呢?咱們再回顧下SwingTest程序,這裏以匿名內部類的方式建立了一個ActionListener接口實例ide
jButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button Pressed!"); } });
使用Lambda表達式改進後函數式編程
jButton.addActionListener(e -> System.out.println("Button Pressed!"));
也就是咱們使用Lambda表達式建立了一個ActionListener接口的實例,再看下ActionListener接口的定義函數
public interface ActionListener extends EventListener { /** * Invoked when an action occurs. */ public void actionPerformed(ActionEvent e); }
只有一個抽象方法,雖然沒添加FunctionalInterface註解,可是也符合函數式接口的定義,編譯器會認爲這是一個函數式接口。
因此,使用Lambda表達式能夠建立函數式接口的實例。即Lambda表達式返回的是函數式接口類型。
實際上,函數式接口實例的建立能夠有三種方式(參考自FunctionalInterface註解說明):
1.Lambda表達式
2.方法引用(後續章節介紹)
3.構造方法引用(後續章節介紹)學習
小結:本篇咱們打開了學習Java8的大門,認識了什麼是lambda表達式,瞭解了函數式接口的定義是什麼,並借住幾個例子展現了lambda表達式的便捷之處,若是以爲本篇文章對你有所幫助幫忙贊一下哈。code