Java Lambda表達式


能夠將Lambda表達式理解爲簡潔地表示可傳遞的匿名函數的一種方式:它沒有名稱,但它有參數列表、函數主體、返回類型,可能還有一個能夠拋出的異常列表。java

  • 匿名 - 由於它不像普通的方法同樣有一個明確的名稱。
  • 函數 - 說它是函數是由於Lambda函數不像方法那樣屬於某個特定的類,但和方法要同樣,Lambda有參數列表、函數主體、返回類型,還可能有能夠拋出的異常列表。
  • 傳遞 - Lambda表達式能夠做爲參數傳遞給方法或存儲在變量中。
  • 簡潔 - 無需像匿名類那樣寫不少模板代碼

    使用Lambda的最終結果就是你的代碼變得更清晰、靈活。打比方,利用Lambda表達式,能夠更爲簡潔地自定義一個Comparator對象。app

1572578326137

舉個例子:函數

java8以前spa

Comparator <Apple> byWeight = new Comparator<Apple>(){
    public int compare(Apple a1,Apple a2){
        return a1.getWeight().compareTo(a2.getWeight());
    }
};

使用lambda表達式code

(Apple a1,Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

lambda表達式由三個部分對象

1572578570347

列出lambda表達式的使用案例blog

1572578712280

1.2在哪裏可使用lambda

1.2.1函數式接口

函數式接口就是只定義一個抽象方法的接口。Lambda表達式容許你直接之內聯的形式爲函數式接口的抽象方法提供實現,並把整個表達式做爲函數式接口的實例。 接口

Predicaterem

java.util.function.Predicate<T>接口定義了一個名叫test的抽象方法,它接受泛型T對象,並返回一個boolean。在須要表示一個涉及類型T的布爾表達式時,就可使用這個接口。get

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

舉個例子使用這個接口

public static <T> List<T> filter(List<T> list, Predicate<T> p){
    List<T> results = new ArrayList<>();
    for (T s: list){
        if(p.test(s)){
            results.add(s);
        }    
    }
    return results;
}

Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

Consumer

java.util.function.Consumer<T>定義了一個名叫accept的抽象方法,它接受泛型T對象,沒有返回(void)。

@FunctionalInterface
public interface Comsumer<T> {
    void accept(T t);
}@FunctionalInterface
public interface Function<T, R> {
    R accept(T t);
}

用這個接口建立一個方法

public static <T> void forEach(List<T> list, Predicate<T> c){
    for (T i: list){
        c.accept(i);
    }
}

forEach(
      Arrays.asList(1,2,3,4,5),
      (Interger i) -> System.ou.println(i)
    );
Function

java.util.function.Function<T, R>定義了一個名叫apply的抽象方法,它接受一個泛型T對象,並返回一個泛型R的對象。

@FunctionalInterface
public interface Function<T, R> {
    R accept(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<Integer> l =map(Arrays.asList("lambdas","in","action"), (String s) -> s.length());

1572580125151

1.3方法引用

方法引用能夠重複使用現有的方法定義,並像Lambda同樣傳遞它們。

先前

invenstory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

使用方法引用和comparing

inventory.sort(comparing(Apple::getWeight));

1.3.1 如何構建方法引用

方法引用主要有三類。

  • 指向靜態方法的方法引用(Integer::parseInt)
  • 指向任意類型實例方法的方法引用(String::length)
  • 指向現有對象的實例方法的方法引用(Transaction::getValue)

下面用圖可讓你更清楚地理解

1572580633506

1.3.2構造函數引用

能夠利用現有構造函數的名稱和關鍵字來建立它的一個引用 ClassName:new

例1:

Supplier<Apple> c1 = Apple::new;
Apple a1 = c1.get();

等價於

Supplier<Apple> c1 = () -> new Apple();
Apple a1 = c1.get();

例2:若是有一個具備兩個參數的構造函數Apple(String color , Integer weight),它就適合BiFunction接口的簽名,能夠這樣寫

BiFunction<String,Integer,Apple> c2 = Apple::new;
Apple c3 = c3.apply("green",110);

例3:若是有三個參數的構造函數呢?Color(int , int , int),你須要本身建立一個與構造函數引用的簽名匹配的函數式接口

1572581604195

1.4 複合Lambda表達式的有用方法

1.4.1 比較器複合

Comparator<Apple> c = Comparator.comparing(Apple::getWeight);

1.逆序

inventory.sort(comparing(Apple::getWeight).reversed());

2.比較器鏈

若是兩個蘋果同樣重怎麼辦,哪一個蘋果應該排在前面?這時候可能須要再提供一個Comparator來進一步比較。
thenComparing 就是作這個用的。它接受一個函數做爲參數(與comparing方法同樣),若是兩個對象用第一個Comparator比較以後是同樣的,就提供第二個Comparator:

inventory.sort(comparing(Apple::getWeight).reversed().thenComparing(Apple::getCountry));

1.4.2謂詞複合

謂詞接口包括三個方法:negate、and和or.

  • 使用negate方法返回一個predicate的非,例如篩選出不是紅色的蘋果
Predicate<Apple> notRedApple = redApple.negate();
  • and
    能夠用and方法將兩個Lambda組合起來:
Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150);
  • or
Predicate<Apple> redAndHeavyAppleOrGreen = redApple.and(a -> a.getWeight() > 150).or(a -> "green".equals(a.getcolor)));

1.4.3 函數複合

還能夠把Function接口所表明的Lambda表達式複合起來。Function接口有兩個默認方法:andThen和 compose。它們都會返回Function的一個實例。

andThen 方法會返回一個函數,它先對輸入應用一個給定函數,再對輸出應用另外一個函數。

好比函數f給數字加1,另外一個函數給數字乘2:

Function<Integer,Integer> f = x -> x + 1;
Function<Integer,Integer> g = x -> x * 2;
Function<Integer,Integer> h = f.andThen(g);
int result = h.apply(1);

在數學上意味着g(f(x))

compose 方法先把給定的函數用做compose的參數裏面給的那個函數,而後再把函數自己用於結果。

Function<Integer,Integer> f = x -> x + 1;
Function<Integer,Integer> g = x -> x * 2;
Function<Integer,Integer> h = f.compose(g);
int result = h.apply(1);

在數學上意味着f(g(x))

相關文章
相關標籤/搜索