【Lambda】之 初識
文章目錄
什麼是Lambda?
有一種數學模型天生適合做並行化,即Lambda表示式。
這個數學模型後來在計算機領域衍生成另一種程式設計正規化,即函數語言程式設計(Function Programming)
lambda表示式允許我們將行為傳到函式裡
傳統集合缺點
- Java的for迴圈是序列的,而且必須按照集合中元素的順序進行一次處理
- 集合框架無法堆控制流進行優化,例如通過排序 並行 短路(short-circuiting)求值以及惰性求值改善效能
lambda優勢
劃分:內部迭代 外部迭代
之前外部迭代 職責:做什麼 (業務需求),怎麼做 (如何遍歷)
之後內部迭代 職責:做什麼
怎麼做則交給類庫
為什麼要學習Lambda?
更好理解函式式,其允許用函式式風格寫程式碼
方便用於對列表(Lists) 和 集合(Collections)資料進行提取,過濾和排序。
需要學習哪些點?
- Lambda表示式
- 函式式介面
- 流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();
語法:
左邊為預期輸入,右邊為預期輸出
- (params) -> expression
- (params) -> statement
- (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()
方法被轉化為並行流)