1. 程式人生 > >【Lambda】之 初識

【Lambda】之 初識

文章目錄

什麼是Lambda?

有一種數學模型天生適合做並行化,即Lambda表示式。

這個數學模型後來在計算機領域衍生成另一種程式設計正規化,即函數語言程式設計(Function Programming)

lambda表示式允許我們將行為傳到函式裡

傳統集合缺點

  1. Java的for迴圈是序列的,而且必須按照集合中元素的順序進行一次處理
  2. 集合框架無法堆控制流進行優化,例如通過排序 並行 短路(short-circuiting)求值以及惰性求值改善效能

lambda優勢

劃分:內部迭代 外部迭代

之前外部迭代 職責:做什麼 (業務需求),怎麼做 (如何遍歷)

之後內部迭代 職責:做什麼

怎麼做則交給類庫

為什麼要學習Lambda?

更好理解函式式,其允許用函式式風格寫程式碼

方便用於對列表(Lists) 和 集合(Collections)資料進行提取,過濾和排序。

需要學習哪些點?

  1. Lambda表示式
  2. 函式式介面
  3. 流API

舉例

用lambda表示式實現Runnable

主要用於 匿名類 時候。

// 之前,通常使用:
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("not use lambda");
    }
}).start();

// 使用lambda後:
new Thread( () -> System.out.println("use lambda")).start();

語法:

左邊為預期輸入,右邊為預期輸出

  1. (params) -> expression
  2. (params) -> statement
  3. (params) -> { statements }
    即用 () -> {} 代替整個匿名類

比如不傳參:
() -> System.out.println("hello lambda!")

接受引數:
(int even, int odd) -> even + odd

用lambda表示式對列表進行迭代

更容易做迭代和對集合元素進行並行處理

List<String> features = Arrays.asList("lambdas", "default", "stream api");
        
// 之前:
for (String feature : features) {
     System.out.println(feature);
}
        
// lambda 之後:
features.forEach(item -> System.out.println(item));
        
// 更簡潔:
features.forEach(System.out::println);

使用lambda表示式和函式式介面Predicate

java.util.function.Predicate 函式式介面,可以向API方法新增邏輯,用更少的程式碼支援更多的動態行為。
Predicate介面適用於做過濾

    public void testPredicate() {

        List<String> languages = Arrays.asList("Java", "JavaScript", "Scala", "C++", "Haskell");

        System.out.println("Language which starts with J: ");
        filter(languages, (str) -> str.startsWith("J"));

        // OR after
        filter2(languages, (str) -> str.startsWith("J"));

    }

    private void filter(List<String> names, Predicate<String> condition) {
        for (String name: names) {
            if (condition.test(name)) {
                System.out.println(name + " ");
            }
        }
    }

    private void filter2(List<String> names, Predicate<String> condition) {
        names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
            System.out.println(name + " ");
        });
    }

Predicate介面允許進行多重條件的測試:

可以將兩個或者多個 Predicate 合成一個。即 and() or() xor()

        Predicate<String> startsWithJ = (n) -> n.startsWith("J");
        Predicate<String> fourLetterLong = (n) -> n.length() == 4;

        languages.stream().filter(startsWithJ.and(fourLetterLong))
                .forEach((n) -> System.out.println("Name, which starts with 'J' and four letter long is : " + n ));

lambda表示式 Map 示例

map 允許將物件(或 值) 進行轉換,流中每一個元素都將進行轉換。

        List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
        
        for (Integer cost : costBeforeTax) {
            double price = cost + .12 * cost;
            System.out.println(price);
        }

        // 使用lambda表示式
        costBeforeTax.stream().map((cost) -> cost + .12 * cost)
                .forEach(System.out::println);

lambda表示式 Reduce 示例

reduce() 又為摺疊操作, 可以將所有值合併成一個。

在 SQL 中類似 sum() avg() count() 聚合函式,實際上就是 reduce 操作。

接受多值,並返回一個值。

        List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
        double total = 0;
        for (Integer cost : costBeforeTax) {
            double price = cost + .12 * cost;
            total = total + price;
        }

        System.out.println("Total : " + total);

        // 之後
        double bill = costBeforeTax.stream().map((cost) -> cost + .12 * cost)
                .reduce((sum, cost) -> sum + cost)
                .get();
        System.out.println("Bill : " + bill);

通過過濾建立一個String列表

lambda 表示式過濾 Java 集合

        List<String> strList = Arrays.asList("English", "Chinese", "French", "KaKoa");

        List<String> filtered = strList.stream().filter(x -> x.length() > 2).collect(Collectors.toList());

        System.out.printf("Original List : %s, filtered list : %s", strList, filtered);

流(stream)

在類庫中議新增新的 流java.util.stream.Stream 以便進行聚集(aggregation)操作

其中,Stream<T> 代表物件引用,此外還有一系列特化(specialization)流,比如IntStream代表整形數字流

流的操作可以被組合成 流水線(pipeline)

例如:

shapes.stream()
      .filter(s -> s.getColor() == BLUE)
      .forEach(s -> s.setColor(RED));

Collection 上呼叫 stream() 會生成該集合元素的流檢視(stream view);
filter() 過濾,產生只包含藍色的流;
forEach() 遍歷,並操作設定為紅色。

流水線既可以序列執行也可以並行執行,並行或序列是流的屬性。
除非顯示要求使用並行流,否則JDK總會返回序列流。(序列流可以通過parallel()方法被轉化為並行流)

參考資料

  1. https://juejin.im/entry/585e6b5f128fe1006dee6329
  2. https://feibhwang.github.io/my_Blog/2017/04/28/Parallelism-Advantages-in-Functional-Programming/
  3. http://www.importnew.com/16436.html