java8之lambda表達式(函數式接口)

在Java中有許多已有的接口都須要封裝代碼塊,例如:Runnable或者Comparator。lambda表達式與這些接口是向後兼容的。對於只包含一個抽象方法的接口,你能夠經過lambda表達式來建立該接口的對象,這種接口被稱爲函數式接口。注意:Java8中接口能夠聲明非抽象的方法java

爲了演示函數式接口轉換,咱們以Arrays.sort方法爲例。該方法的第二個參數須要一個Comparator接口(該接口只含有一個方法)的實例。接下來咱們編寫一個簡單的lambda表達式:編程

Arrays.sort(words,(first,second) -> Integer.compare(first.length(),second.length()));

在這個表達式背後,Arrays.sort方法會接收一個實現了Comparaotr<String>接口的類的實例。調用該對象的compare方法會執行lambda表達式中的代碼。這些對象和類的管理徹底依賴於如何實現,所以比傳統的內部類效率更高。你最好將一個lambda表達式想象成一個函數,而不是一個對象,並記住它能夠被轉換爲一個函數式接口。編程語言

事實上,函數式接口的轉換是你在java中使用lambda表達式能作的惟一一件事。在其餘支持函數文本的編程語言中,你能夠聲明像(String,String) -> int這樣的函數類型,聲明這種類型的變量,並使用這些變量來保存函數表達式。可是,java設計者們仍是決定堅持使用熟悉的接口概念,而沒有將函數類型添加到java中。函數式編程

Java API在java.util.function包中定義了許多很是通用的函數式接口(後面blog會進行詳細講解)。其中接口BiFunction<T,U,R>描述了T和U類型的方法參數以及返回類型R。你能夠將咱們的字符串比較lambda表達式保存在一個該類型的變量中:函數

BiFunction<String,String,Integer> comp = 
    (first,second) -> Integer.compare(first.length(),second.length());

可是,這對排序並不能起到什麼幫助做用。不存在接收BiFunction做爲參數的Arrays.sort方法。若是你以前使用過其餘函數式編程語言,你可能會對此感到奇怪。可是對於Java開發人員來講,這再天然不過了。像Comparator這樣的接口有着特定的目的,而不單單是一個接收參數和返回類型的方法。Java8保留了這一習慣。當你但願使用lambda表達式時,你仍然要牢記表達式的目的,併爲它指定一個函數式接口。spa

如今java8自己的API使用了java.util.function中的接口,未來這些接口極可能被應用在各個地方。可是請記住,任何一個lambda表達式均可以等價轉換成如今所使用的API中對應的函數式接口。設計

注意:你能夠在任意函數式接口上標註@FunctionalInterface註解,這樣作有兩個好處。首先,編譯器會檢查標註該註解的實體,檢查它是不是隻包含一個抽象方法的接口。另外,在javadoc頁面也會包含一條聲明,說明這個接口是一個函數式接口。該註解並不要求強制使用。從概念上來說,全部只含有一個抽象方法的接口都是函數式接口,可是使用@FunctionalInterface註解會讓你代碼看上去更清楚。code

最後,當一個lambda表達式被轉換爲一個函數式接口的實例時,請注意處理檢查期異常。若是lambda表達式中可能會拋出一個檢查期異常,那麼該異常須要在目標接口的抽象方法中進行聲明。例如,如下表達式會產生一個錯誤:對象

//錯誤:Thread.sleep能夠拋出一個檢查期的InterruptedException
Runnable sleeper = () -> {System.out.println("Zzz");Thread.sleep(1000);};

因爲Runnable.run不能拋出任何異常,因此這個賦值是不合法的。有兩種方法能夠修正該問題。一種是在lambda表達式中捕獲異常,另外一種是將lambda表達式賦值給一個其抽象方法能夠拋出異常的接口。例如,Callable接口的call方法能夠拋出任何異常。
blog

相關文章
相關標籤/搜索