什麼是 Lambda 表達式,我以爲是咱們開始學習 Lambda 表達式以前應該要弄清楚的一個概念。咱們能夠把 Lambda 表達式理解爲簡潔地表示能夠傳遞的匿名函數的一種方式:它沒有名稱,但它有參數列表、函數主體、返回類型,可能還有一個能夠拋出的異常列表。1
簡單的說 Lambda 有如下的特色:
1.匿名,它沒有一個明確的名字。
2.函數,是的, Lambda 表達式確實是一種函數,這毋庸置疑。
3.傳遞,Lambda 表達式能夠做爲參數傳遞給方法。
4.簡潔,沒有什麼比 Lambda 更加簡潔的語法了(Java 中)java
概念說完咱們就開始咱們的代碼之旅——Lambda 的語法:
(paramenters) -> expression
或者
(paramenters) -> { statements; }
數據庫
Lambda 參數
+ 箭頭
+ Lambda 主體
構成。在 Java8 中 Lambda 表達式的體現形式有如下 5 中:
1.(String s) -> s.length()
這個 Lambda 表達式具備一個 String 類型的參數而且返回一個 Int。2express
2.(Apple a) -> a.getWeight() > 150
這個 Lambda 表達式具備一個 Apple 類型的參數而且返回一個 Boolean。多線程
3.(int x, int y) -> (System.out.println(x + y))
這個 Lambda 表達式具備一個 String 類型的參數然而它並無返回值(void 返回)。hexo
4.() -> 93
這個 Lambda 表達式沒有參數,返回一個 Int。app
5.(Apple a, Apple b) -> a1.getWeight().compareTo(a2.getWeight())
最後一個 Lambda 表達式具備兩個 Apple 類型的參數,返回一個 Int。函數
咱們剛剛已經瞭解了 Lambda 表達式的語法以及基本的 5 中表現形式,那麼應該在哪裏使用 Lambda 表達式以及如何使用 Lambda 表達式呢?通常咱們能夠在函數式接口3上使用 Lambda 表達式。附錄 A 列舉了 JDK 8以前已有的函數式接口。學習
咱們最經常使用的應該是 java.lang.Runnable 接口了,在 Java8 以前要開啓一個多線程,那麼一定會寫如下這段代碼:flex
Runnable run = new Runnable(){ public void run(){ System.out.println("Start a new Thread"); } };
按照正常的縮進,咱們開啓一個線程最少須要寫 5 行代碼,其中只有一行使咱們的主要核心,其餘 4 行代碼都是爲之服務的,或者稱之爲樣板式代碼。有點像 JDBC 數據庫鏈接池同樣,先要建立鏈接對象...最後關閉鏈接池。而使用 Lambda 表達式能夠有效的縮短代碼的行數,而且讓代碼寫的更加的清晰。線程
Runnable run = () -> System.out.println("Start a new Thread");
沒錯,就這麼簡單,一切顯得是那麼的優雅和華麗,沒有什麼多餘的樣板式代碼,一眼就可以看代碼的意圖。不再用主動過濾掉無用的代碼了,應爲留下來的都是有用的代碼。可能你一時還不習慣這樣的方式或是寫法,不要緊接着往下,會有更多的列子和驚喜。
剛剛咱們用函數式接口來使用 Lambda 表達式,還有一種方式是使用函數描述符——函數式接口的抽象方法基本上就是 Lambda 表達式的簽名。就拿剛剛線程的代碼來講,Runnable 接口能夠看作一個什麼都沒有返回的的函數簽名,應爲它只有一個 run 的抽象方法,這個方法既不接受參數也不返回參數。
public void process(Runnable r){ r.run(); } process(() -> System.out.println("Start a new Thread"));
廢話很少說,先上代碼:
public class ExecuteAround { public static void main(String ...args) throws IOException{ // method we want to refactor to make more flexible String result = processFileLimited(); System.out.println(result); System.out.println("---"); // 使用 Lambda 表達式改進 String oneLine = processFile((BufferedReader b) -> b.readLine()); System.out.println(oneLine); String twoLines = processFile((BufferedReader b) -> b.readLine() + b.readLine()); System.out.println(twoLines); } public static String processFileLimited() throws IOException { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) { return br.readLine(); } } public static String processFile(BufferedReaderProcessor p) throws IOException { try(BufferedReader br = new BufferedReader(new FileReader("data.txt"))){ return p.process(br); } } public interface BufferedReaderProcessor{ public String process(BufferedReader b) throws IOException; } }
這個例子就是咱們平時處理資源的一段代碼,咱們打開一個資源,作一些處理(讀啊,寫啊),而後關閉資源。這裏對比了使用傳統方式和使用 Lambda 表達式的方式來寫這一段代碼。這裏能夠看出使用 Lambda 表達式可使代碼更加靈活,在這段代碼中的提現是:能夠由傳入參數的不一樣而決定方法的實現。
正如前面說的,函數式接口定義且只定義了一個抽象方法。咱們在 JDK8 以前經常使用的如 Comparable、Runnable 和 Callable 等,在 Java8 中偉大的設計師又引進了幾個新的函數式接口,這裏介紹其中的一些做爲了解。
java.util.function.Predicate
@FunctionalInterface public interface Predicate<T>{ boolean test(T t); } public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){ List<Apple> result = new ArrayList<>(); for(Apple apple : inventory){ if(p.test(apple)){ result.add(apple); } } return result; } List<Apple> greenApples = filter(inventory, (Apple a) -> "green".equals(a.getColor())); System.out.println(greenApples);
java.util.function.Consumer
@FunctionalInterface public interface Consumer<T>{ void accept(T t); } public static <T> forEach(List<T> list, Consumer<T> c){ for(T i: list){ c.accept(i); } } List<int> list = Arrays.asList(1, 2, 3, 4, 5); //Lambda 是 Consumer 中 accept 方法的實現 forEach(list, (Integer i) -> System.out.println(i))
java.util.function.Function<T, R> 接口定義了一個叫作 apply 的方法,該方法接受一個泛型的 T 對象,返回一個泛型的 R 對象。若是你須要一個 Lambda 表達式將對象的信息映射到輸出,那麼久可使用這個接口。
@FunctionalInterface public interface Function<T, R>{ R apply(T t); } public static <T, R> List<R> map(List<T> list, Function<T, R> f){ List<R> result = new ArrayList<>(); for(T s: list){ result.add(f.apply(s)); } return result; } List<int> list = Arrays.asList("java8", "in", "action"); List<Interger> listFun = map { list,(String s) -> s.length(); };
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
本文由我的 hexo 博客 co2fe.com 遷移
date: 2017-07-16 22:03:37