lambda初體驗

Lambda語法詳解

我們在此抽象一下lambda表達式的一般語法:

(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}

 

從lambda表達式的一般語法可以看出來,還是挺符合上面給出的非精確版本的定義–“一段帶有輸入參數的可執行語句塊”。

上面的lambda表達式語法可以認爲是最全的版本,寫起來還是稍稍有些繁瑣。彆着急,下面陸續介紹一下lambda表達式的各種簡化版:

1. 參數類型省略–絕大多數情況,編譯器都可以從上下文環境中推斷出lambda表達式的參數類型。這樣lambda表達式就變成了:

(param1,param2, ..., paramN) -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}

 

所以我們最開始的例子就變成了(省略了List的創建):

List<String> lowercaseNames = names.stream().map((name) -> {return name.toLowerCase();}).collect(Collectors.toList());

2. 當lambda表達式的參數個數只有一個,可以省略小括號。lambda表達式簡寫爲:

param1 -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}

 所以最開始的例子再次簡化爲:

List<String> lowercaseNames = names.stream().map(name -> {return name.toLowerCase();}).collect(Collectors.toList());

 

3. 當lambda表達式只包含一條語句時,可以省略大括號、return和語句結尾的分號。lambda表達式簡化爲:

param1 -> statment

所以最開始的例子再次簡化爲:

List<String> lowercaseNames = names.stream().map(name -> name.toLowerCase()).collect(Collectors.toList());

4. 使用Method Reference(具體語法後面介紹)

//注意,這段代碼在Idea 13.0.2中顯示有錯誤,但是可以正常運行
List<String> lowercaseNames = names.stream().map(String::toLowerCase).collect(Collectors.toList());


我們前面所有的介紹,感覺上lambda表達式像一個閉關鎖國的傢伙,可以訪問給它傳遞的參數,也能自己內部定義變量。但是卻從來沒看到其訪問它外部的變量。是不是lambda表達式不能訪問其外部變量?我們可以這樣想:lambda表達式其實是快速創建SAM接口的語法糖,原先的SAM接口都可以訪問接口外部變量,lambda表達式肯定也是可以(不但可以,在java8中還做了一個小小的升級,後面會介紹)。

Lambda表達式眼中的外部世界

String[] array = {"a", "b", "c"};
for(Integer i : Lists.newArrayList(1,2,3)){
  Stream.of(array).map(item -> Strings.padEnd(item, i, '@')).forEach(System.out::println);
}

上面的這個例子中,map中的lambda表達式訪問外部變量Integer i。並且可以訪問外部變量是lambda表達式的一個重要特性,這樣我們可以看出來lambda表達式的三個重要組成部分:

  • 輸入參數
  • 可執行語句
  • 存放外部變量的空間

不過lambda表達式訪問外部變量有一個非常重要的限制:變量不可變(只是引用不可變,而不是真正的不可變)。

String[] array = {"a", "b", "c"};
for(int i = 1; i<4; i++){
  Stream.of(array).map(item -> Strings.padEnd(item, i, '@')).forEach(System.out::println);
}

上面的代碼,會報編譯錯誤。因爲變量i被lambda表達式引用,所以編譯器會隱式的把其當成final來處理(ps:大家可以想象問什麼上一個例子不報錯,而這個報錯。)細心的讀者肯定會發現不對啊,以前java的匿名內部類在訪問外部變量的時候,外部變量必須用final修飾。Bingo,在java8對這個限制做了優化(前面說的小小優化),可以不用顯示使用final修飾,但是編譯器隱式當成final來處理。

Stream.of(array).map(item -> Strings.padEnd(item, i, '@')).forEach(System.out::println);


lambda眼中的this

在lambda中,this不是指向lambda表達式產生的那個SAM對象,而是聲明它的外部對象。

 

Java8 新增的函數式api存放於 java.util.function 下,提供了大多數常用的函數式接口

1、Predicate:斷言型接口
    // 傳入的字符串是否以 .sql 結尾
    Predicate<String> isEndWithSql = (s) -> s.endsWith(".sql");

    // 傳入的字符串非 .sql 結尾
    Predicate<String> notEndWithSql = isEndWithSql.negate();

    boolean test = isEndWithSql.test("test.sql");
    System.out.println(test);

    boolean test1 = notEndWithSql.test("test.sql");
    System.out.println(test1);

    // 判斷集合是否爲空
    Predicate<List<String>> isEmptyList = List::isEmpty;

2、Function:功能型接口
    
    // 字符串轉爲 Integer
    Function<String,Integer> toInteger = s -> Integer.valueOf(s); 

    System.out.println(toInteger.apply("222"));

    toInteger = Integer::valueOf;

    System.out.println(toInteger.apply("222"));


    Function 中的 default 方法:
        andThen:在 Function 執行之後
        compose:在 Function 執行之前

3、Supplier:供給型接口
    
    Supplier<StringBuilder> sbSupplier = StringBuilder::new;

    StringBuilder sb = sbSupplier.get();

4、Consumer:消費型接口

    Consumer<Runnable> runnableConsumer = (run) -> new Thread(run).start();

    runnableConsumer.accept(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {

        }
        System.out.println("測試一下了");
    });

public void test(){

Consumer<String> con = System.out::println;

con.accept("測試一下了");

}


public void test2(){

Supplier<Date> sup = Date::new;

Date date1 = sup.get();

Date date2 = sup.get();

System.out.println(date1 == date2);

}


public void test3(){

Function<Integer,String[]> fun = String[]::new;

String[] strArr = fun.apply(10);

System.out.println(strArr);

}


public void test4(){

Predicate<Integer> predicate = x -> x > 10;

boolean test = predicate.test(10);

System.out.println(test);

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章