摘要:自從出來(lái)過(guò)后,引入了流,函數(shù)式編程,就更不是在向著面向?qū)ο蟀l(fā)展了。下面我就來(lái)探索一下,到底解決了一些什么問(wèn)題。一個(gè)簡(jiǎn)單的原則是要處理的問(wèn)題規(guī)模很龐大,或處理單個(gè)問(wèn)題特別耗時(shí)就可以考慮多線(xiàn)程了。
在學(xué)習(xí)面向?qū)ο髸r(shí),許多人都會(huì)用Java來(lái)舉例子,但是其實(shí)Java并非純正的面向?qū)ο笳Z(yǔ)言,最明顯的就是:int,double等基本類(lèi)型不是對(duì)象。
自從java8出來(lái)過(guò)后,引入了流,函數(shù)式編程,就更不是在向著面向?qū)ο蟀l(fā)展了。有人可能會(huì)感到詫異,為啥越來(lái)越偏離我們遵循了這么久的面向?qū)ο笤O(shè)計(jì)模式?
其實(shí)很簡(jiǎn)單,我們對(duì)工具的改造的最終目的都是為了解決問(wèn)題,以前有面向過(guò)程解決不了的問(wèn)題,那么面向?qū)ο蟪鰜?lái)解決了;現(xiàn)在面向?qū)ο笥性S多問(wèn)題,那么就可以用函數(shù)式編程來(lái)解決,所以這些變化是很自然的,Java要在不同時(shí)代的保持自己的活力,就必須與時(shí)俱進(jìn),所以Java8的出現(xiàn)就是自然而然的。
下面我就來(lái)探索一下,Java8到底解決了一些什么問(wèn)題。
消除冗余類(lèi)代碼假設(shè)有個(gè)類(lèi):
class People{ private String name; private int age; public People(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
現(xiàn)在有個(gè)list
Listworkers = new LinkedList<>(); workers.add( new People("aa",23)); workers.add( new People("abc",21)); workers.add( new People("cdf",18));
如果要對(duì)這個(gè)list按照People的年齡排序,并打印出來(lái),那么在Java8之前會(huì)這樣寫(xiě):
workers.sort(new Comparator() { @Override public int compare(People o1, People o2) { return o1.getAge()>o2.getAge()?1:-1; } }); for (People p:workers ) { System.out.println(p.getName()+":"+p.getAge()); }
Java8引入了函數(shù)式編程的lambda表達(dá)式,就可以這樣寫(xiě)了:
workers.sort((o1, o2) -> o1.getAge()>o2.getAge()?1:-1); for (People p:workers ) { System.out.println(p.getName()+":"+p.getAge()); }
進(jìn)一步,使用方法引用就可以這樣寫(xiě):
workers.sort(Comparator.comparing(People::getAge)); for (People p:workers ) { System.out.println(p.getName()+":"+p.getAge()); }
這樣就更簡(jiǎn)潔了,而且意圖也和清晰,可以不寫(xiě)注釋就能讓別人明白,是按照年齡排序。
函數(shù)式的lambda表達(dá)式通過(guò)將函數(shù)提升為“一等公民”,使得直接傳遞函數(shù)成為可能,而不必再為了傳遞實(shí)現(xiàn)某個(gè)功能的函數(shù)而強(qiáng)行傳遞一個(gè)冗余的外包類(lèi)。
內(nèi)部迭代替代外部迭代stream允許你以聲明性方式處理數(shù)據(jù)集合,類(lèi)似于SQL語(yǔ)句。我們直接看例子吧,上面那一段代碼已經(jīng)很簡(jiǎn)潔了,但是使用了流還可以更簡(jiǎn)潔
workers.sort(Comparator.comparing(People::getAge)); workers.stream().map(p-> p.getName()+":"+p.getAge()).forEach(System.out::println);
這一段代碼根本就沒(méi)有循環(huán)了,Stream API 替你搞定了循環(huán),這就是內(nèi)部迭代 替代 外部迭代 ,
亦即API的設(shè)計(jì)者 替 使用者完成了迭代,代碼相當(dāng)簡(jiǎn)潔。
而且由于是內(nèi)部迭代,所以Stream庫(kù)可以選擇最適合本機(jī)硬件的實(shí)現(xiàn),達(dá)到性能優(yōu)化的目的,如果是外部迭代,就需要調(diào)用者自己來(lái)優(yōu)化了(你得承認(rèn)許多API調(diào)用者沒(méi)有這種優(yōu)化能力)。
如果我們有大量數(shù)據(jù)要處理,通常會(huì)使用多線(xiàn)程,在Java8之前,使用多線(xiàn)程是一件比較麻煩的事:
我們得自己合理的劃分?jǐn)?shù)據(jù)
手動(dòng)為每一部分?jǐn)?shù)據(jù)多帶帶分配一個(gè)線(xiàn)程,還有可能會(huì)產(chǎn)生競(jìng)態(tài)條件需要進(jìn)行同步
完成每個(gè)線(xiàn)程的結(jié)果的合并,得到最終結(jié)果。
這個(gè)過(guò)程是比較麻煩的,易錯(cuò)的。使用流能夠安全簡(jiǎn)潔的使用多核,甚至于你都不需要關(guān)心多線(xiàn)程的具體實(shí)現(xiàn)。
傳統(tǒng)的循環(huán):
ListintList = new LinkedList(); for (int i=0;i<20_000_000;i++){ intList.add(i+""); } long count = 0; long start = System.nanoTime(); for (String in:intList ) { if (Integer.parseInt(in)>1_123_345) count++; } long duration = (System.nanoTime() - start) / 1_000_000; System.out.println(duration);
結(jié)果:781,747,770
Java8的并行流:
ListintList = new LinkedList(); for (int i=0;i<20_000_000;i++){ intList.add(i+""); } long count = 0; long start = System.nanoTime(); count = intList.parallelStream().filter(p->Integer.parseInt(p)>1_123_345).count(); long duration = (System.nanoTime() - start) / 1_000_000; System.out.println(duration);
結(jié)果:665,683,662
可見(jiàn)我們并不需要顯式的進(jìn)行多線(xiàn)程編程就能取得比單線(xiàn)程更好的結(jié)果,也就是Stream庫(kù)幫我們實(shí)現(xiàn)了多線(xiàn)程,更安全(不得不承認(rèn)許多人寫(xiě)的多線(xiàn)程代碼都是有問(wèn)題的),更簡(jiǎn)潔(我們不用寫(xiě)多線(xiàn)程代碼了)。
稍微需要注意的是,多線(xiàn)程本身會(huì)帶來(lái)一定開(kāi)銷(xiāo),所以如果問(wèn)題規(guī)模不夠大的話(huà)(具體數(shù)值取決于你的硬件),單線(xiàn)程反而優(yōu)于多線(xiàn)程,所以使用之前要先考慮和測(cè)試,多線(xiàn)程到底能否帶來(lái)好處。一個(gè)簡(jiǎn)單的原則是:要處理的問(wèn)題規(guī)模很龐大,或處理單個(gè)問(wèn)題特別耗時(shí)就可以考慮多線(xiàn)程了。
總之,Java8還有好多新特性,會(huì)幫我們解決許多以前無(wú)法解決的問(wèn)題,所以我們要與時(shí)俱進(jìn),好好學(xué)習(xí)?。▇_~)。
歡迎反問(wèn)我的主頁(yè),Mageek(http://mageek.cn)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/70106.html
摘要:依舊使用剛剛對(duì)蘋(píng)果排序的代碼?,F(xiàn)在,要做的是篩選出所有的綠蘋(píng)果,也許你會(huì)這一個(gè)這樣的方法在之前,基本上都是這樣寫(xiě)的,看起來(lái)也沒(méi)什么毛病。但是,現(xiàn)在又要篩選一下重量超過(guò)克的蘋(píng)果。 《Java8實(shí)戰(zhàn)》-讀書(shū)筆記第一章(01) 最近一直想寫(xiě)點(diǎn)什么東西,卻不知該怎么寫(xiě),所以就寫(xiě)寫(xiě)關(guān)于看《Java8實(shí)戰(zhàn)》的筆記吧。 第一章內(nèi)容較多,因此打算分幾篇文章來(lái)寫(xiě)。 為什么要關(guān)心Java8 自1996年J...
摘要:實(shí)戰(zhàn)讀書(shū)筆記第一章從方法傳遞到接著上次的,繼續(xù)來(lái)了解一下,如果繼續(xù)簡(jiǎn)化代碼。去掉并且生成的數(shù)字是萬(wàn),所消耗的時(shí)間循序流并行流至于為什么有時(shí)候并行流效率比循序流還低,這個(gè)以后的文章會(huì)解釋。 《Java8實(shí)戰(zhàn)》-讀書(shū)筆記第一章(02) 從方法傳遞到Lambda 接著上次的Predicate,繼續(xù)來(lái)了解一下,如果繼續(xù)簡(jiǎn)化代碼。 把方法作為值來(lái)傳遞雖然很有用,但是要是有很多類(lèi)似與isHeavy...
摘要:注意當(dāng)多個(gè)父接口中存在相同的默認(rèn)方法時(shí),子類(lèi)中以就近原則繼承。定義靜態(tài)默認(rèn)方法這是版簡(jiǎn)易計(jì)算器接口默認(rèn)方法使用定義接口并提供默認(rèn)打印方法定義接口默認(rèn)方法支持方法形參這是數(shù)值運(yùn)算基本接口。。。 總概 JAVA8 已經(jīng)發(fā)布很久,而且毫無(wú)疑問(wèn),java8是自java5(2004年發(fā)布)之后的最重要的版本。其中包括語(yǔ)言、編譯器、庫(kù)、工具和JVM等諸多方面的新特性。 Java8 新特性列表如下:...
摘要:使用解決的數(shù)據(jù)流問(wèn)題原文譯者飛龍協(xié)議在年三月發(fā)布,距離現(xiàn)在年三月五號(hào)快有一年了。除了,最實(shí)用的特性是新的數(shù)據(jù)流。是吧,注是瀏覽器上的數(shù)據(jù)流的接口,并解決了上述問(wèn)題。 使用Intellij IDEA 解決Java8的數(shù)據(jù)流問(wèn)題 原文:Fixing Java 8 Stream Gotchas with IntelliJ IDEA 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 ...
大概一年多之前,我對(duì)java8的理解還僅限一些只言片語(yǔ)的文章之上,后來(lái)出于對(duì)函數(shù)式編程的興趣,買(mǎi)了本參考書(shū)看了一遍,然后放在了書(shū)架上,后來(lái),當(dāng)我接手大客戶(hù)應(yīng)用的開(kāi)發(fā)工作之后,java8的一些工具,對(duì)我的效率有了不小的提升,因此想記錄一下java8的一些常用場(chǎng)景,我希望這會(huì)成為一個(gè)小字典,能讓我免于頻繁翻書(shū),但是總能找到自己想找的知識(shí)。 用于舉例的model: @Data public class ...
閱讀 1697·2019-08-30 15:44
閱讀 2628·2019-08-30 11:19
閱讀 465·2019-08-30 11:06
閱讀 1650·2019-08-29 15:27
閱讀 3132·2019-08-29 13:44
閱讀 1674·2019-08-28 18:28
閱讀 2408·2019-08-28 18:17
閱讀 2117·2019-08-26 10:41