自從使用上了Java8的Lambda和Stream編程后,徹底的愛(ài)上了症歇。因此決定研究下其他新特性郎笆。
Lambda表達(dá)式
什么是lambda表達(dá)式谭梗?lambda表達(dá)式就是一個(gè)匿名函數(shù),是一段可以傳遞的代碼题画。表達(dá)式表達(dá)式默辨,你可以理解為就是一堆表達(dá)式以函數(shù)形式封裝在一起,只不過(guò)沒(méi)有函數(shù)名苍息。這堆表達(dá)式可以被一個(gè)引用持有缩幸,傳遞這個(gè)引用就是傳遞這個(gè)匿名函數(shù)。
但是我們知道竞思,Java中所有的東西都是類或者接口表谊,那lambda應(yīng)該屬于類還是接口呢?答案就是lambda屬于函數(shù)式接口盖喷,就是只有一個(gè)方法的接口爆办。只有接口只有一個(gè)方法,那么他就可以用lambda來(lái)表示课梳,比如Runnable距辆、Callable、Comparator接口暮刃。Java8還新增了幾個(gè)通用的函數(shù)式接口:Function跨算、Comsumer、Supplier椭懊、Predicate诸蚕。
- Function:函數(shù)型接口,輸入一個(gè)入?yún)⒀踱敵鲆粋€(gè)出參
- Consumer接口:消費(fèi)型接口背犯,輸入一個(gè)入?yún)ⅲ瑹o(wú)返回值盅抚,形象的理解就是把參數(shù)吃(消費(fèi))了
- Supplier:供給型接口漠魏,無(wú)入?yún)ⅲ祷匾粋€(gè)值妄均。形象理解就是你不用給我提供什么東西蛉幸,我供給你一些東西。
- Predicate:斷言型接口丛晦,接收一個(gè)參數(shù)奕纫,返回一個(gè)boolean值。
lambda表達(dá)式的作用有:
- 簡(jiǎn)化部分匿名內(nèi)部類的寫法:為什么是部分呢烫沙?因?yàn)閘ambda只能簡(jiǎn)化接口只有函數(shù)式接口的匿名內(nèi)部類匹层。函數(shù)式接口只有一個(gè)未實(shí)現(xiàn)的函數(shù),你使用lambda匿名函數(shù)就是實(shí)現(xiàn)該接口。如果匿名內(nèi)部類有多個(gè)未實(shí)現(xiàn)的方法升筏,當(dāng)然就不能使用lambda表達(dá)式類取代了撑柔。
綜上,lambda就是一個(gè)函數(shù)式接口您访,可以自己寫一個(gè)函數(shù)式接口來(lái)接收l(shuí)ambda铅忿,或者使用Java提供的通用的接口Function、Consumer灵汪、Supplier檀训、Predicate接口。
函數(shù)式接口
就是只有一個(gè)方法的接口享言,可以使用@FunctionInterface注解加到接口上峻凫,約束該接口不能超過(guò)兩個(gè)方法。當(dāng)然不加該注解也可以览露。
方法引用與構(gòu)造器引用
其實(shí)就是lambda的更進(jìn)一步的簡(jiǎn)寫荧琼。
方法引用:和lambda類似,寫lambda表達(dá)式時(shí)需要你手動(dòng)寫一堆表達(dá)式差牛,如果這堆表達(dá)式其實(shí)某個(gè)方法已經(jīng)實(shí)現(xiàn)了命锄,則不需要再寫lambda了,只需要傳入方法引用即可偏化。主要有三種表達(dá)方式:
- 對(duì)象::實(shí)例方法名
- 類::靜態(tài)方法名
- 類::實(shí)例方法名:上面都是把參數(shù)對(duì)應(yīng)到參數(shù)列表脐恩,這種方式則不是,本來(lái)方法參數(shù)需要和參數(shù)列表對(duì)應(yīng)夹孔,但如果方法的第一個(gè)參數(shù)是該參數(shù)實(shí)例,則可以用這種方法析孽。比如搭伤,你如果想寫 (a) -> a.getName(); 則完全可以寫為A::getName
例如你要寫一個(gè)大于String的lambda,一般是:
Consumer<String> c = x -> System.out.println(x);
你可以發(fā)現(xiàn)袜瞬,這個(gè)打印的動(dòng)作是你手動(dòng)寫表達(dá)式做的怜俐,即System.out.println(x),其實(shí)打印的動(dòng)作System.out這個(gè)實(shí)例的println已經(jīng)實(shí)現(xiàn)了邓尤,那么可以使用方法引用如下:
Consumer<String> c = System.out::println;
構(gòu)造器引用拍鲤,類名::new。用來(lái)生成一個(gè)對(duì)象汞扎。如果一個(gè)類有多個(gè)構(gòu)造器季稳,則new選用哪個(gè)構(gòu)造器取決于方法入?yún)ⅰ?/p>
如果要調(diào)用無(wú)參構(gòu)造器,則用供給型接口:
Supplier<Employee> s = Employee::new;
如果要調(diào)用單個(gè)參數(shù)的構(gòu)造器澈魄,則使用函數(shù)型接口:
Function<Integer, Employee> f = Employee::new;
由上可知景鼠,一個(gè)引用可以對(duì)應(yīng)到不同的重載方法,具體使用的是哪個(gè)方法痹扇,要看你接收的函數(shù)型接口的參數(shù)铛漓。
Stream API
流式操作溯香,Stream不會(huì)改變?cè)醇希ㄟ^(guò)Stream操作后會(huì)生成流浓恶。標(biāo)準(zhǔn)的Stream操作是:
- 通過(guò)集合創(chuàng)建Stream流玫坛,一般是.stream()方法
- 做操作
- 終止操作,生成新集合
Optional類
自我感覺(jué)不好用包晰,不做介紹湿镀,這是用來(lái)避免空指針的,我覺(jué)得還不如用Spring的Assert來(lái)斷言比較好
接口中的默認(rèn)方法與靜態(tài)方法
Java8后杜窄,接口中可以有已經(jīng)實(shí)現(xiàn)的默認(rèn)方法肠骆。接口中也可以有靜態(tài)實(shí)現(xiàn)的方法。
新時(shí)間日期API
Java8以前的日期Date不易使用塞耕,同時(shí)日期格式化類SimpleDateFormatter存在線程安全問(wèn)題蚀腿。Java8新出的幾個(gè)日期類型則非常的易用
- LocalDate:日期類型
- LocalTime:時(shí)間類型
- LocalDateTime:日期時(shí)間類型
- Instant:時(shí)間戳,of方法是從1970-01-01開始算起
- Duration:計(jì)算兩個(gè)時(shí)間之間的間隔扫外,Duration.between(LocalTime, LocalTime)
- Period:計(jì)算兩個(gè)日期之間的間隔莉钙,Period.between(LocalDate, LocalDate)
- TemporalAdjuster:時(shí)間校正器,如筛谚,獲取下一個(gè)周六磁玉,LocalDateTime.now().with(TemporalAdjusters.next(DayOfWeek.SATURDAY))
- DateTimeFormatter:時(shí)間日期格式化
- ZoneId:時(shí)區(qū)轉(zhuǎn)化