提升你的代码——Lambda!
歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計(jì)與實(shí)踐原理》和《RabbitMQ實(shí)戰(zhàn)指南》,同時(shí)歡迎關(guān)注筆者的微信公眾號(hào):朱小廝的博客。
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/java/java-lambda-quick-start/
前言
上個(gè)月(2018年2月)看過一份調(diào)研報(bào)告,對(duì)于Java版本而言,生產(chǎn)環(huán)境中用的最多的是JDk6和JDK7,雖然JDK8在自2014年3月發(fā)布至今使用占比仍然很小,想想月底JDK10都要出來(lái)了呀。JDk8引入了很多新的特性,比如接口默認(rèn)值、方法引用、Lambda表達(dá)式、函數(shù)式接口、Optional、Stream等等,這些在其他語(yǔ)言中并不少見的玩意兒,現(xiàn)今在Java中卻還很少使用,很多時(shí)候我們會(huì)對(duì)新事物(其實(shí)已經(jīng)不新鮮)抱著一種比較保守的態(tài)度:反正我司還沒用到,學(xué)了也無(wú)用武之地;讓別人先去踩踩坑、我來(lái)大樹底下好乘涼;又學(xué)新東西?我JDK7都沒學(xué)完,又TMD要學(xué)JDk8、9、10?累覺不愛啊,筆者也一直保持著這種心態(tài),但是一顆好奇的心促使我小小的往前邁了那么一小步……
好奇之心
平常擼代碼的時(shí)候經(jīng)常也會(huì)涉及一些多線程的東西,比如使用Future和Callable來(lái)搞一些事情,代碼舉例如下:
對(duì)于這段代碼在搞什么事情這里就不多說(shuō)了,值得注意的是IDEA里給“new Callable()”這段代碼“特殊”照顧了一下(注意IDE的language level要設(shè)置成JDK8及以上的),想必是要告訴我一些隱晦的事情,本著一顆少男的好奇心我默默的瀏覽了下提示信息,詳細(xì)如下圖:
內(nèi)心的躁動(dòng)讓我小小點(diǎn)擊了“Replace with lambda”一下?代碼迅速地做了切換:
What an AMAZING thing! 代碼立馬簡(jiǎn)潔了許多,整個(gè)Callable接口的實(shí)現(xiàn)只保留了關(guān)鍵的“()->“l(fā)ambda demo””。這個(gè)不止在使用Callable的時(shí)候發(fā)生,常用的Runnable、Comparator中都會(huì)如此,JDK8到底對(duì)它們做了什么改變?! 我們不妨舉一個(gè)DEMO從最初的夙愿來(lái)一步步撥開這一層層面紗~~
循序漸進(jìn)
DEMO需求:對(duì)一個(gè)數(shù)字型的字符串列表做排序,這個(gè)列表很簡(jiǎn)單,具體如下:
List<String> list = Arrays.asList("2", "3", "1", "4");這個(gè)需求很簡(jiǎn)單,實(shí)現(xiàn)起來(lái)不需要1分鐘:
Comparator<String> comparator = new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return Integer.valueOf(o1) - Integer.valueOf(o2);} }; list.sort(comparator);注意本文中所使用的JDK版本為8,所以你看到List的sort()方法的時(shí)候不要感到太意外,這是List接口中用默認(rèn)方法實(shí)現(xiàn)的一個(gè)新方法:default void sort(Comparator<? super E> c)。對(duì)于上面的實(shí)現(xiàn)我們還可以很傲嬌的改用一下匿名類的方式:
list.sort(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return Integer.valueOf(o1) - Integer.valueOf(o2);} });如果是JDK7,那么用一下Collections.sort()方法,然后差不多實(shí)現(xiàn)到這里就結(jié)束了,然后JDK8才剛剛開始,我們可以通過進(jìn)一步的把這個(gè)方法改為L(zhǎng)ambda表達(dá)式的形式實(shí)現(xiàn):
list.sort((String o1, String o2) -> Integer.valueOf(o1) - Integer.valueOf(o2));好了,一下子就變成一行代碼了,只不過看上去比原先的有那么一丟丟的晦澀。正如上面所說(shuō)的Callable也好、Runnable也好,和Comparator這種都屬于函數(shù)式接口,如果你打開源碼可以發(fā)現(xiàn)這三個(gè)接口都有一個(gè)相同的注解——@FuncationalInterface。如果你所使用的方法中包含有函數(shù)式接口,那么你就可以使用Lambda表達(dá)式。函數(shù)式接口是一種有且只有一個(gè)抽象方法的接口,如果標(biāo)注為@FunctionalInterface的接口沒有抽象方法(空接口也就是標(biāo)記接口,或者接口中的方法都是默認(rèn)方法)或者擁有超過一個(gè)抽象方法的話都會(huì)報(bào)錯(cuò)。
類似于( //會(huì)報(bào)錯(cuò):No target method found.):
或者這樣(//會(huì)報(bào)錯(cuò):Multiple non-overriding abstract methods found in interface FunctionError):
@FunctionalInterface public interface FunctionError{public String method1(String o1, String o2);public String method2(Integer o1, Boolean o2); }都是無(wú)效的,可以將上面的其中一個(gè)方法改為默認(rèn)方法:
@FunctionalInterface public interface FunctionCorrect{public String method1(String o1, String o2);default public String method2(Integer o1, Boolean o2){return "why not rabbitmq or kafka?";}; }這樣就沒有問題。
這里我們先來(lái)小結(jié)一下——Lambda表達(dá)式一個(gè)有三個(gè)部分:
可以看到Lambda的基本語(yǔ)法為:
或者:
(參數(shù)列表)-> {語(yǔ)句}Java還可以推斷出Lambda表達(dá)式中的參數(shù)類型,上面的代碼還可以進(jìn)一步優(yōu)化去掉參數(shù)類型的聲明:
list.sort((o1, o2) -> Integer.valueOf(o1) - Integer.valueOf(o2));對(duì)于上面的代碼中Integer本身就具有“可比性”(實(shí)現(xiàn)了Comparable)接口,上面的代碼可以改寫成:
list.sort((o1, o2) -> Integer.valueOf(o1).compareTo(Integer.valueOf(o2)));不過這樣的代碼易讀性好像也不是很高,我們這里做進(jìn)一步的改進(jìn),這里引入了一個(gè)新的概念——方法引用。方法引用讓你可以重復(fù)使用現(xiàn)有的方法定義,并像Lambda一樣傳遞他們,在某些情況下,他們更加的易讀。上面的代碼可以進(jìn)一步的改寫成:
list.sort(Comparator.comparing(Integer::valueOf));這樣的代碼可以看出我們對(duì)于String列表的排序規(guī)則時(shí)其int類型的值,而不用再關(guān)注有點(diǎn)晦澀的Lambda語(yǔ)句。如果有一天寶寶不開心了,不按照其轉(zhuǎn)換的int值排序,而是按照其hashCode排序怎么辦呢,很簡(jiǎn)單:
list.sort(Comparator.comparing(String::hashCode));如果寶寶又不開了,原本是升序排序的,現(xiàn)在要按降序排序的怎么辦呢?改寫Lambda表達(dá)式,比如這樣:
list.sort((o1, o2) -> Integer.valueOf(o2).compareTo(Integer.valueOf(o1)));不如這樣:
list.sort(Comparator.comparing(Integer::valueOf).reversed()); //or list.sort(Comparator.comparing(String::hashCode).reversed());是不是通俗易懂又方便?方法引用的基本思想是:如果一個(gè)Lambda代表的只是直接調(diào)用這個(gè)方法,那最好還是用名稱來(lái)調(diào)用它,而不是去描述如何調(diào)用它。事實(shí)上,方法引用就是讓你根據(jù)已有的方法實(shí)現(xiàn)來(lái)創(chuàng)建Lambda表達(dá)式,只不過顯示地指明方法的名稱,代碼可讀性會(huì)高一點(diǎn)。當(dāng)你需要使用方法引用時(shí),將目標(biāo)引用放在分隔符::前,而方法的名稱放在后面。例如:
(String s) -> System.out.println(s) 可以等效為 System.out:println要不你try一下下面的代碼看看效果是不是一樣的?
public class FunctionDemo {@FunctionalInterfacepublic interface FunctionQuote{public void print(String arg);}public static void process(FunctionQuote functionQuote){String str = "http://blog.csdn.net/u013256816";functionQuote.print(str);}public static void main(String[] args) {process((String s) -> System.out.println(s));process(System.out::println);} }歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/java/java-lambda-quick-start/
歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計(jì)與實(shí)踐原理》和《RabbitMQ實(shí)戰(zhàn)指南》,同時(shí)歡迎關(guān)注筆者的微信公眾號(hào):朱小廝的博客。
總結(jié)
以上是生活随笔為你收集整理的提升你的代码——Lambda!的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kafka解析之topic创建(2)
- 下一篇: 集群管理工具KafkaAdminClie