對于一個新事物拒啰,我們應該從這三方面來認識驯绎,是什么完慧?為什么會出現(xiàn)谋旦?怎么用?
一屈尼、Lambda表達式是什么?
它是Java8的一個新特性册着,正如學習一門新語言要先自己手寫一個HelloWorld一樣,我們先寫一個Lambda表達式的HelloWorld脾歧。比如遍歷輸出一個List:
List<String> list = new ArrayList<String>();
list.add("renheng");
list.add("fangmiao");
//java8以前遍歷集合
for(String str : list){
System.out.println(str);
}
//使用Lamada表達式遍歷集合
list.stream().forEach(str -> System.out.println(str));
1.Lambda表達式的形式化表示如下所示
Parameters -> an expression
2.如果Lambda表達式中要執(zhí)行多個語句塊,需要將多個語句塊以{}進行包裝甲捏,如果有返回值,需要顯示指定return語句鞭执,如下所示:
Parameters -> {expressions;};
3.如果Lambda表達式不需要參數(shù)司顿,可以使用一個空括號表示芒粹,如下示例所示
() -> {for (int i = 0; i < 1000; i++) doSomething();};
二、Lambda表達式有哪些方便之處大溜?
lambda表達式化漆,它將允許我們將行為傳到函數(shù)里。在Java 8之前钦奋,如果想將行為傳入函數(shù)座云,僅有的選擇就是匿名類,需要6行代碼付材。而定義行為最重要的那行代碼朦拖,卻混在中間不夠突出。Lambda表達式取代了匿名類厌衔,取消了模板璧帝,允許用函數(shù)式風格編寫代碼。這樣有時可讀性更好葵诈,表達更清晰裸弦。在Java生態(tài)系統(tǒng)中,函數(shù)式表達與對面向對象的全面支持是個激動人心的進步作喘。將進一步促進并行第三方庫的發(fā)展理疙,充分利用多核CPU。我認為任何嚴謹?shù)腏ava開發(fā)者都不應忽視此次Java發(fā)布的核心特性泞坦,即lambda表達式窖贤、函數(shù)式接口、流API贰锁、默認方法和新的Date以及Time API赃梧。作為開發(fā)人員,我發(fā)現(xiàn)學習和掌握lambda表達式的最佳方法就是勇于嘗試豌熄,盡可能多練習lambda表達式例子授嘀。鑒于受Java 8發(fā)布的影響最大的是Java集合框架(Java Collections framework),所以最好練習流API和lambda表達式锣险,用于對列表(Lists)和集合(Collections)數(shù)據(jù)進行提取蹄皱、過濾和排序。下面是Lambda表達式的幾個應用芯肤。
三巷折、怎么使用Lambda表達式?
1.使用Lambda表達式代替匿名內部類:
那就是用() -> {}代碼塊替代了整個匿名類:
比如給一個按鈕添加監(jiān)聽事件崖咨,當點擊時在控制臺打印一行字符串锻拘。
Button button = new Button("點擊");
//java8以前
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("點擊了我一下");
}
});
//java8
button.addActionListener((e) -> System.out.println("點擊了我一下"));
再比如想對一個Integer列表進行降序排序輸出:
List<Integer> list = Lists.newArrayList(1,2,9,5,10,11);
//java8以前
Collections.sort(list, new Comparator(){
@Override
public int compare(Object ob1, Object ob2) {
Integer a = (Integer)ob1;
Integer b = (Integer)ob2;
return b - a;
}
});
//java8
Collections.sort(list, (a,b) -> b-a);
Collectons的sort方法默認是按升序排列,如果要按降序排列击蹲,需要重寫Comparator接口的compare方法署拟。發(fā)現(xiàn)使用Lambda表達式一行代碼就搞定婉宰!
2.流Stream
2.1 filter():對流過濾
任務:創(chuàng)建一個姓氏集合,要求出所有初始字母為L的人的總數(shù)目推穷。使用流處理的代碼如下:
List<String> list = Lists.newArrayList("Ren","Liu","Li","Lu");
Long count = list.stream().filter(a -> a.startsWith("L")).count();
System.out.println("以L開頭的姓氏有" + count + "個");
2.2 map():將集合類(例如列表)元素進行轉換
任務:對工資表中超過3500的部分征收20%的稅芍阎,得到稅后的工資表。
使用流處理的代碼如下:
List<Double> salaryBeforeTax = Lists.newArrayList(4000.0,5500.0,6000.0,7000.0);
List<Double> salaryAfterTax = salaryBeforeTax.stream().map(a -> a - (a-3500)*0.2).collect(Collectors.toList());
map方法對流中的每一個對象進行繳稅操作缨恒,得到稅后的工資谴咸,然后使用collect方法將這些新值轉換成一個新的list。其中Collectors有toList方法骗露,還有toSet岭佳、toMap方法等,看你想得到什么類型的集合了萧锉。
任務:將姓氏列表中的值全部轉換成大寫字母
List<String> list = Lists.newArrayList("Ren","Liu","Li","Lu");
List<String> upperList = list.stream().map(a -> a.toUpperCase()).collect(Collectors.toList());
2.3 reduce: reduce() 函數(shù)可以將所有值合并成一個,又被稱為折疊操作,SQL中類似 sum()珊随、avg() 或者 count() 的聚集函數(shù),實際上就是 reduce 操作柿隙,因為它們接收多個值并返回一個值叶洞。
任務:對工資表超過3500的部分進行扣稅(20%),并將稅后的值進行相加計算總和禀崖。
List<Double> salaryBeforeTax = Lists.newArrayList(4000.0,5500.0,6000.0,7000.0);
Double sum = salaryBeforeTax.stream().map(a -> a-(a-3500)*0.2).reduce((s,b) -> s+b).get();
System.out.println(sum);
//1.無初始值累加
T t = salaryBeforeTax.stream().reduce((a,b)->a+b);
//2.帶初始值累加
Optional<T> t = salaryBeforeTax.stream().reduce("1",(a,b)->a+b);
2.4對列表的每個元素應用函數(shù)
我們通常需要對列表的每個元素使用某個函數(shù)衩辟,例如逐一乘以某個數(shù)、除以某個數(shù)或者做其它操作波附。這些操作都很適合用 map() 方法艺晴,可以將轉換邏輯以lambda表達式的形式放在 map() 方法里,就可以對集合的各個元素進行轉換了掸屡,如下所示封寞。
// 將字符串換成大寫并用逗號鏈接起來
List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada");
String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
System.out.println(G7Countries);
輸出:USA, JAPAN, FRANCE, GERMANY, ITALY, U.K., CANADA
2.5利用流的 distinct() 方法來對集合進行去重。
// 用所有不同的數(shù)字創(chuàng)建一個正方形列表
List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
List<Integer> distinct = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
輸出:81, 100, 9, 16, 49
2.6計算集合元素的最大值仅财、最小值狈究、總和以及平均值
IntStream、LongStream 和 DoubleStream 等流的類中盏求,有個非常有用的方法叫做 summaryStatistics() 抖锥。可以返回 IntSummaryStatistics风喇、LongSummaryStatistics 或者 DoubleSummaryStatistic s宁改,描述流中元素的各種摘要數(shù)據(jù)缕探。在本例中魂莫,我們用這個方法來計算列表的最大值和最小值。它也有 getSum() 和 getAverage() 方法來獲得列表的所有元素的總和及平均值爹耗。
List<Double> salaryBeforeTax = Lists.newArrayList(4000.0,5500.0,6000.0,7000.0);
DoubleSummaryStatistics summary = salaryBeforeTax.stream().mapToDouble(a -> a).summaryStatistics();
System.out.println("最高工資:" + summary.getMax());
System.out.println("最低工資:" + summary.getMin());
System.out.println("平均工資:" + summary.getAverage());
System.out.println("工資總計:" + summary.getSum());
輸出:
最高工資:7000.0
最低工資:4000.0
平均工資:5625.0
工資總計:22500.0
2.7 flatMap:把多個流合并為一個流
List<Integer> list1 = Lists.newArrayList(1,2,3);
List<Integer> list2 = Lists.newArrayList(4,5,6);
List<Integer> all = Stream.of(list1,list2).flatMap(a -> a.stream()).collect(Collectors.toList());
for(Integer n:all){
System.out.print(n);
}
輸出:123456