這篇文章給大家介紹lambda表達(dá)式如何正確的在Java8項(xiàng)目中使用,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
公司主營(yíng)業(yè)務(wù):做網(wǎng)站、成都網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)建站是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)建站推出瀘水免費(fèi)做網(wǎng)站回饋大家。
在Java8 里面Lambda是最火的主題,不僅僅是因?yàn)檎Z(yǔ)法的改變,更重要的是帶來(lái)了函數(shù)式編程的思想,我覺(jué)得優(yōu)秀的程序員,有必要學(xué)習(xí)一下函數(shù)式編程的思想以開闊思路。所以這篇文章聊聊Lambda的應(yīng)用場(chǎng)景,性能,也會(huì)提及下不好的一面。
Java為何需要Lambda
1996年1月,Java 1.0發(fā)布了,此后計(jì)算機(jī)編程領(lǐng)域發(fā)生了翻天覆地的變化。商業(yè)發(fā)展需要更復(fù)雜的應(yīng)用,大多數(shù)程序都跑在更強(qiáng)大的裝備多核CPU的機(jī)器上。帶有高效運(yùn)行期編譯器的Java虛擬機(jī)(JVM)的出現(xiàn),使得程序員將精力更多放在編寫干凈、易于維護(hù)的代碼上,而不是思考如何將每一個(gè)CPU時(shí)鐘、每一字節(jié)內(nèi)存物盡其用。
多核CPU的出現(xiàn)成了“房間里的大象”,無(wú)法忽視卻沒(méi)人愿意正視。算法中引入鎖不但容易出錯(cuò),而且消耗時(shí)間。人們開發(fā)了java.util.concurrent包和很多第三方類庫(kù),試圖將并發(fā)抽象化,用以幫助程序員寫出在多核CPU上運(yùn)行良好的程序。不幸的是,到目前為止,我們走得還不夠遠(yuǎn)。
那些類庫(kù)的開發(fā)者使用Java時(shí),發(fā)現(xiàn)抽象的級(jí)別還不夠。處理大數(shù)據(jù)就是個(gè)很好的例子,面對(duì)大數(shù)據(jù),Java還欠缺高效的并行操作。Java 8允許開發(fā)者編寫復(fù)雜的集合處理算法,只需要簡(jiǎn)單修改一個(gè)方法,就能讓代碼在多核CPU上高效運(yùn)行。為了編寫并行處理這些大數(shù)據(jù)的類庫(kù),需要在語(yǔ)言層面上修改現(xiàn)有的Java:增加lambda表達(dá)式。
當(dāng)然,這樣做是有代價(jià)的,程序員必須學(xué)習(xí)如何編寫和閱讀包含lambda表達(dá)式的代碼,但是,這不是一樁賠本的買賣。與手寫一大段復(fù)雜的、線程安全的代碼相比,學(xué)習(xí)一點(diǎn)新語(yǔ)法和一些新習(xí)慣容易很多。開發(fā)企業(yè)級(jí)應(yīng)用時(shí),好的類庫(kù)和框架極大地降低了開發(fā)時(shí)間和成本,也掃清了開發(fā)易用且高效的類庫(kù)的障礙。
Lambda的應(yīng)用場(chǎng)景
下面我將重點(diǎn)放在函數(shù)式編程的實(shí)用性上,包括那些可以被大多數(shù)程序員理解和使用的技術(shù),我們關(guān)心的如何寫出好代碼,而不是符合函數(shù)編程風(fēng)格的代碼。
1.1.1 1.使用() -> {} 替代匿名類
現(xiàn)在Runnable線程,Swing,JavaFX的事件監(jiān)聽器代碼等,在java 8中你可以使用Lambda表達(dá)式替代丑陋的匿名類。
//Before Java 8: new Thread(new Runnable() { @Override public void run() { System.out.println("Before Java8 "); } }).start(); //Java 8 way: new Thread(() -> System.out.println("In Java8!")); // Before Java 8: JButton show = new JButton("Show"); show.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("without lambda expression is boring"); } }); // Java 8 way: show.addActionListener((e) -> { System.out.println("Action !! Lambda expressions Rocks"); });
使用內(nèi)循環(huán)替代外循環(huán)
外循環(huán):描述怎么干,代碼里嵌套2個(gè)以上的for循環(huán)的都比較難讀懂;只能順序處理List中的元素;
內(nèi)循環(huán):描述要干什么,而不是怎么干;不一定需要順序處理List中的元素
//Prior Java 8 : List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API"); for (String feature : features) { System.out.println(feature); } //In Java 8: List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API"); features.forEach(n -> System.out.println(n)); // Even better use Method reference feature of Java 8 // method reference is denoted by :: (double colon) operator // looks similar to score resolution operator of C++ features.forEach(System.out::println); Output: Lambdas Default Method Stream API Date and Time API
支持函數(shù)編程
為了支持函數(shù)編程,Java 8加入了一個(gè)新的包java.util.function,其中有一個(gè)接口java.util.function.Predicate是支持Lambda函數(shù)編程:
public static void main(args[]){ List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp"); System.out.println("Languages which starts with J :"); filter(languages, (str)->str.startsWith("J")); System.out.println("Languages which ends with a "); filter(languages, (str)->str.endsWith("a")); System.out.println("Print all languages :"); filter(languages, (str)->true); System.out.println("Print no language : "); filter(languages, (str)->false); System.out.println("Print language whose length greater than 4:"); filter(languages, (str)->str.length() > 4); } public static void filter(List names, Predicate condition) { names.stream().filter((name) -> (condition.test(name))) .forEach((name) -> {System.out.println(name + " "); }); }
Output: Languages which starts with J : Java Languages which ends with a Java Scala Print all languages : Java Scala C++ Haskell Lisp Print no language : Print language whose length greater than 4: Scala Haskell
處理數(shù)據(jù)?用管道的方式更加簡(jiǎn)潔
Java 8里面新增的Stream API ,讓集合中的數(shù)據(jù)處理起來(lái)更加方便,性能更高,可讀性更好
假設(shè)一個(gè)業(yè)務(wù)場(chǎng)景:對(duì)于20元以上的商品,進(jìn)行9折處理,最后得到這些商品的折后價(jià)格。
final BigDecimal totalOfDiscountedPrices = prices.stream() .filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0) .map(price -> price.multiply(BigDecimal.valueOf(0.9))) .reduce(BigDecimal.ZERO,BigDecimal::add); System.out.println("Total of discounted prices: " + totalOfDiscountedPrices);
想象一下:如果用面向?qū)ο筇幚磉@些數(shù)據(jù),需要多少行?多少次循環(huán)?需要聲明多少個(gè)中間變量?
Lambda的陰暗面
前面都是講Lambda如何改變Java程序員的思維習(xí)慣,但Lambda確實(shí)也帶來(lái)了困惑
JVM可以執(zhí)行任何語(yǔ)言編寫的代碼,只要它們能編譯成字節(jié)碼,字節(jié)碼自身是充分OO的,被設(shè)計(jì)成接近于Java語(yǔ)言,這意味著Java被編譯成的字節(jié)碼非常容易被重新組裝。
但是如果不是Java語(yǔ)言,差距將越來(lái)越大,Scala源碼和被編譯成的字節(jié)碼之間巨大差距是一個(gè)證明,編譯器加入了大量合成類 方法和變量,以便讓JVM按照語(yǔ)言自身特定語(yǔ)法和流程控制執(zhí)行。
我們首先看看Java 6/7中的一個(gè)傳統(tǒng)方法案例:
// simple check against empty strings public static int check(String s) { if (s.equals("")) { throw new IllegalArgumentException(); } return s.length(); } //map names to lengths List lengths = new ArrayList(); for (String name : Arrays.asList(args)) { lengths.add(check(name)); }
如果一個(gè)空的字符串傳入,這段代碼將拋出錯(cuò)誤,堆棧跟蹤如下:
at LmbdaMain.check(LmbdaMain.java:19) at LmbdaMain.main(LmbdaMain.java:34)
再看看Lambda的例子
Stream lengths = names.stream().map(name -> check(name)); at LmbdaMain.check(LmbdaMain.java:19) at LmbdaMain.lambda$0(LmbdaMain.java:37) at LmbdaMain$$Lambda$1/821270929.apply(Unknown Source) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.LongPipeline.reduce(LongPipeline.java:438) at java.util.stream.LongPipeline.sum(LongPipeline.java:396) at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526) at LmbdaMain.main(LmbdaMain.java:39)
這非常類似Scala,出錯(cuò)棧信息太長(zhǎng),我們?yōu)榇a的精簡(jiǎn)付出力代價(jià),更精確的代碼意味著更復(fù)雜的調(diào)試。
但這并不影響我們喜歡Lambda!
總結(jié)
在Java世界里面,面向?qū)ο筮€是主流思想,對(duì)于習(xí)慣了面向?qū)ο缶幊痰拈_發(fā)者來(lái)說(shuō),抽象的概念并不陌生。面向?qū)ο缶幊淌菍?duì)數(shù)據(jù)進(jìn)行抽象,而函數(shù)式編程是對(duì)行為進(jìn)行抽象?,F(xiàn)實(shí)世界中,數(shù)據(jù)和行為并存,程序也是如此,因此這兩種編程方式我們都得學(xué)。
這種新的抽象方式還有其他好處。很多人不總是在編寫性能優(yōu)先的代碼,對(duì)于這些人來(lái)說(shuō),函數(shù)式編程帶來(lái)的好處尤為明顯。程序員能編寫出更容易閱讀的代碼——這種代碼更多地表達(dá)了業(yè)務(wù)邏輯,而不是從機(jī)制上如何實(shí)現(xiàn)。易讀的代碼也易于維護(hù)、更可靠、更不容易出錯(cuò)。
在寫回調(diào)函數(shù)和事件處理器時(shí),程序員不必再糾纏于匿名內(nèi)部類的冗繁和可讀性,函數(shù)式編程讓事件處理系統(tǒng)變得更加簡(jiǎn)單。能將函數(shù)方便地傳遞也讓編寫惰性代碼變得容易,只有在真正需要的時(shí)候,才初始化變量的值。
總而言之,Java更趨于完美了。
關(guān)于lambda表達(dá)式如何正確的在Java8項(xiàng)目中使用就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
網(wǎng)頁(yè)題目:lambda表達(dá)式如何正確的在Java8項(xiàng)目中使用
文章路徑:http://chinadenli.net/article12/gijigc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、標(biāo)簽優(yōu)化、響應(yīng)式網(wǎng)站、企業(yè)網(wǎng)站制作、網(wǎng)站排名、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)