Java8發(fā)布已經(jīng)有一段時(shí)間了簸呈,這次發(fā)布的改動(dòng)比較大额港,很多人將這次改動(dòng)與Java5的升級(jí)相提并論样屠。Java8其中一個(gè)很重要的新特性就是lambda表達(dá)式,允許我們將行為傳到函數(shù)中蛹磺。想想看粟瞬,在Java8 之前我們想要將行為傳入函數(shù),僅有的選擇就是匿名內(nèi)部類萤捆。
Java8發(fā)布以后裙品,lambda表達(dá)式將大量替代匿名內(nèi)部類的使用,簡(jiǎn)化代碼的同時(shí)俗或,更突出了原來(lái)匿名內(nèi)部類中最重要的那部分包含真正邏輯的代碼市怎。尤其是對(duì)于做數(shù)據(jù)的同學(xué)來(lái)說(shuō),當(dāng)習(xí)慣使用類似scala之類的函數(shù)式編程語(yǔ)言以后辛慰,體會(huì)將更加深刻∏常現(xiàn)在我們就來(lái)看看Java8中l(wèi)ambda表達(dá)式的一些常見寫法。
lambda體中調(diào)用方法的參數(shù)列表和返回值類型,要和函數(shù)式接口中抽象方法的參數(shù)列表和返回值類型保持一致驰弄。
一麻汰、替代匿名內(nèi)部類
lambda表達(dá)式用的最多的場(chǎng)合就是替代匿名內(nèi)部類,實(shí)現(xiàn)Runnable接口是匿名內(nèi)部類的經(jīng)典例子戚篙。lambda表達(dá)式的功能相當(dāng)強(qiáng)大五鲫,用()->就可以代替整個(gè)匿名內(nèi)部類!
packageOSChina.Lambda;
importorg.junit.Test;
importjava.util.Comparator;
importjava.util.function.Consumer;
importjava.util.function.Function;
importjava.util.function.Predicate;
importjava.util.function.Supplier;
publicclassTest1{
publicstaticvoidmain(String[]?args){
Runnable?runnable?=newRunnable()?{
@Override
publicvoidrun(){
System.out.println("普通岔擂,線程啟動(dòng)");
}
};
runnable.run();
test2();
test3();
test4();
test5();
}
//無(wú)參數(shù)位喂,無(wú)返回值
publicstaticvoidtest2(){
//“->”左邊只有一個(gè)小括號(hào),表示無(wú)參數(shù)乱灵,右邊是Lambda體(就相當(dāng)于實(shí)現(xiàn)了匿名內(nèi)部類里面的方法了塑崖,(即就是一個(gè)可用的接口實(shí)現(xiàn)類了。))
Runnable?runnable?=?()->System.out.println("Lambda?表達(dá)式方式痛倚,線程啟動(dòng)");
runnable.run();
}
//有一個(gè)參數(shù)规婆,并且無(wú)返回值
publicstaticvoidtest3(){
//這個(gè)e就代表所實(shí)現(xiàn)的接口的方法的參數(shù),
Consumer?consumer?=?e->System.out.println("Lambda?表達(dá)式方式蝉稳,"+e);
consumer.accept("傳入?yún)?shù)");
}
//有兩個(gè)以上的參數(shù)聋呢,有返回值,并且?Lambda?體中有多條語(yǔ)句
publicstaticvoidtest4(){
//Lambda 體中有多條語(yǔ)句颠区,記得要用大括號(hào)括起來(lái)
Comparator?com?=?(x,?y)?->?{
System.out.println("函數(shù)式接口");
returnInteger.compare(x,?y);
};
intcompare?=?com.compare(100,244);
System.out.println("有兩個(gè)以上的參數(shù),有返回值,"+compare);
}
//若?Lambda?體中只有一條語(yǔ)句通铲,?return?和?大括號(hào)都可以省略不寫
publicstaticvoidtest5(){
//Comparator?com?=?(x,?y)?->?Integer.compare(100,?244);
System.out.println("若?Lambda?體中只有一條語(yǔ)句毕莱,?return?和?大括號(hào)都可以省略不寫,"+Integer.compare(100,244));
}
}
二、Java8四大內(nèi)置函數(shù)式接口
如果使用lambda還要自己寫一個(gè)接口的話太麻煩颅夺,所以Java自己提供了一些接口:
1朋截、Consumer 消費(fèi)性接口:void accept(T t);
//有一個(gè)參數(shù)吧黄,并且無(wú)返回值
publicstaticvoidtest3(){
//這個(gè)e就代表所實(shí)現(xiàn)的接口的方法的參數(shù)部服,
Consumer?consumer?=?e->System.out.println("Lambda?表達(dá)式方式,"+e);
consumer.accept("傳入?yún)?shù)");
}
2拗慨、Supplier供給型接口:T get();
package?OSChina.Lambda;
importjava.util.ArrayList;
importjava.util.function.Supplier;
publicclassTest2{
publicstaticvoidmain(String[]?args){
ArrayList?res?=?getNumList(10,()->(int)(Math.random()*100));
System.out.println(res);
}
publicstaticArrayList?getNumList(intnum,?Supplier?sup){
ArrayListlist=newArrayList<>();
for(inti?=0;?i?<?num;?i++)?{
Integer?e?=?sup.get();
list.add(e);
}
returnlist;
}
}
3廓八、Function 函數(shù)式接口:R apply(T t);
packageOSChina.Lambda;
importjava.util.function.Function;
publicclassTest2{
publicstatic?void?main(String[]?args)?{
String?newStr?=?strHandler("abc",(str)->str.toUpperCase());
System.out.println(newStr);
newStr?=?strHandler("??abc??",(str)->str.trim());
System.out.println(newStr);
}
publicstatic?String?strHandler(String?str,?Functionfun){
returnfun.apply(str);
}
}
4、Predicate 斷言式接口:boolean test(T t);
判斷一些字符串?dāng)?shù)組判斷長(zhǎng)度>2的字符串:
package?OSChina.Lambda;
importjava.util.ArrayList;
importjava.util.Arrays;
importjava.util.List;
importjava.util.function.Predicate;
publicclassTest2{
publicstaticvoidmain(String[]?args)?{
List?list?=?Arrays.asList("hello","jiangshuying","lambda","www","ok","q");
List?ret?=?filterStr(list,(str)->str.length()>2);
System.out.println(ret);
}
publicstaticList?filterStr(List?list,?Predicate?pre){
ArrayList?arrayList?=newArrayList<>();
for(Stringstr:list){
if(pre.test(str))?{
arrayList.add(str);
}
}
returnarrayList;
}
}
三赵抢、方法引用與構(gòu)造器引用
要求:實(shí)現(xiàn)抽象方法的參數(shù)列表和返回值類型剧蹂,必須與方法引用的方法的參數(shù)列表和返回值類型保持一致!
方法引用:使用操作符“::”將類與方法分隔開來(lái)烦却。
對(duì)象::實(shí)例方法名
類::靜態(tài)方法名
類::實(shí)例方法名
舉個(gè)例子:
publicstaticvoidtest9(){
Comparator?comparator?=?(x,y)->Integer.compare(x,y);
Comparator?comparator1?=?Integer::compare;
intcompare?=?comparator.compare(1,2);
intcompare1?=?comparator1.compare(1,2);
System.out.println("compare:"+compare);
System.out.println("compare1:"+compare1);
}
四宠叼、lambda表達(dá)式的一些常見用法
1、使用lambda表達(dá)式對(duì)集合進(jìn)行迭代
package?OSChina.Lambda;
importjava.util.Arrays;
importjava.util.List;
publicclassTest3{
publicstaticvoidmain(String[]?args){
Listlist=?Arrays.asList("java","c#","javascript");
//before?java8
for(String?str:list){
System.out.println("before?java8,"+str);
}
//after?java8
list.forEach(x->?System.out.println("after?java8,"+x));
}
}
2其爵、用lambda表達(dá)式實(shí)現(xiàn)map
map函數(shù)可以說(shuō)是函數(shù)式編程里最重要的一個(gè)方法了冒冬。map的作用是將一個(gè)對(duì)象變換為另外一個(gè)伸蚯。在我們的例子中,就是通過(guò)map方法將cost增加了0,05倍的大小然后輸出简烤。
package?OSChina.Lambda;
importjava.util.Arrays;
importjava.util.List;
publicclassTest3{
publicstaticvoidmain(String[]?args){
Listlist=?Arrays.asList(10.0,20.0,30.0);
list.stream().map(x->x+x*0.05).forEach(x->?System.out.println(x));
}
}
3剂邮、用lambda表達(dá)式實(shí)現(xiàn)map與reduce
既然提到了map,又怎能不提到reduce乐埠。reduce與map一樣抗斤,也是函數(shù)式編程里最重要的幾個(gè)方法之一,map的作用是將一個(gè)對(duì)象變?yōu)榱硗庖粋€(gè)丈咐,而reduce實(shí)現(xiàn)的則是將所有值合并為一個(gè)瑞眼,請(qǐng)看:
package?OSChina.Lambda;
importjava.util.Arrays;
importjava.util.List;
publicclassTest3{
publicstaticvoidmain(String[]?args){
//before?java8
List?cost?=?Arrays.asList(10.0,20.0,30.0);
doublesum?=0;
for(doubleeach:cost)?{
each?+=?each?*0.05;
sum?+=?each;
}
System.out.println("before?java8,"+sum);
//after?java8
Listlist=?Arrays.asList(10.0,20.0,30.0);
doublesum2?=list.stream().map(x->x+x*0.05).reduce((sum1,x)->sum1+x).get();
System.out.println("after?java8,"+sum2);
}
}
相信用map+reduce+lambda表達(dá)式的寫法高出不止一個(gè)level。
4棵逊、filter操作
filter也是我們經(jīng)常使用的一個(gè)操作伤疙。在操作集合的時(shí)候,經(jīng)常需要從原始的集合中過(guò)濾掉一部分元素辆影。
packageOSChina.Lambda;
importjava.util.Arrays;
importjava.util.List;
importjava.util.stream.Collectors;
publicclassTest3{
publicstaticvoidmain(String[]?args){
List?cost?=?Arrays.asList(10.0,20.0,30.0,40.0);
List?filteredCost?=?cost.stream().filter(x?->?x?>25.0).collect(Collectors.toList());
filteredCost.forEach(x?->?System.out.println(x));
}
}
5徒像、與函數(shù)式接口Predicate配合
除了在語(yǔ)言層面支持函數(shù)式編程風(fēng)格,Java 8也添加了一個(gè)包蛙讥,叫做java.util.function锯蛀。它包含了很多類,用來(lái)支持Java的函數(shù)式編程次慢。
其中一個(gè)便是Predicate旁涤,使用java.util.function.Predicate函數(shù)式接口以及l(fā)ambda表達(dá)式,可以向API方法添加邏輯迫像,用更少的代碼支持更多的動(dòng)態(tài)行為劈愚。Predicate接口非常適用于做過(guò)濾。
package?OSChina.Lambda;
import?java.lang.reflect.Array;
import?java.util.Arrays;
import?java.util.List;
import?java.util.function.Predicate;
publicclassTest4{
publicstaticvoid?filterTest(List?languages,?Predicate?condition)?{
languages.stream().filter(x?->?condition.test(x)).forEach(x?->?System.out.println(x?+"?"));
}
publicstaticvoid?main(String[]?args)?{
List?languages?=?Arrays.asList("Java","Python","scala","Shell","R");
filterTest(languages,x->x.startsWith("J"));//Java?
filterTest(languages,x?->?x.endsWith("a"));//Java,scala?
filterTest(languages,x?->?true);//Java,Python,scala,Shell,R
filterTest(languages,x?->?false);//
filterTest(languages,x?->?x.length()?>4);//Python,scala,Shell,
}
}