Java開發(fā)者還不了解這兩點(diǎn)技術(shù),你的飯碗可要小心了

? ? ? ? 作為一名Java開發(fā)者谢翎,JDK是其必備的開發(fā)工具,如今JDK已經(jīng)更新到了JDK11沐旨,可是最近我發(fā)現(xiàn)很多有過多年Java開發(fā)經(jīng)驗(yàn)的開發(fā)者森逮,居然還在使用JDK6或者更早的版本,或者使用了JDK8磁携,但是對(duì)JDK8及其之后版本的一些新特性完全不了解褒侧,要知道JDK8可是在2013年就正式發(fā)布了。小編自從嘗試了JDK8帶來的快感后谊迄,對(duì)于每次JDK新版本的發(fā)布闷供,總是抱有很大的期待,雖然每次JDK版本的正式發(fā)布统诺,總是帶來不少的新特性和重要改進(jìn)歪脏,不過遺憾的是,JDK8之后版本的新特性對(duì)于一個(gè)著重Java應(yīng)用開發(fā)的開發(fā)者來說感覺并不明顯粮呢,感覺最明顯的還是JDK8婿失,引入的Lambda表達(dá)式和Stream編程。

一啄寡、Lambda表達(dá)式

? ? ? ? Lambda表達(dá)式簡單理解即函數(shù)式編程移怯,其并非Java獨(dú)有,很多編程語言都有这难,如python舟误、c++。 在JDK8之前姻乓,Java是不支持函數(shù)式編程的嵌溢,所謂的函數(shù)編程,即可理解是將一個(gè)函數(shù)(也稱為“行為”)作為一個(gè)參數(shù)進(jìn)行傳遞蹋岩。通常我們提及得更多的是面向?qū)ο缶幊汤挡荩嫦驅(qū)ο缶幊淌菍?duì)數(shù)據(jù)的抽象,而函數(shù)式編程則是對(duì)行為的抽象(將行為作為一個(gè)參數(shù)進(jìn)行傳遞)剪个。 Java 中的 Lambda 表達(dá)式通常使用 (argument) -> (expression) 語法書寫秧骑,例如:

(arg1, arg2...) -> { expression }

(type1 arg1, type2 arg2...) -> { expression }

以下是一些 Lambda 表達(dá)式的例子:

(int a, int b) -> {? return a + b; }

() -> System.out.println("Hello 2019");

(String s) -> { System.out.println(s); }

() -> 30

() -> { return 4 };

通過上面的例子,可以簡單了解一下 Lambda 表達(dá)式的結(jié)構(gòu):

1,一個(gè) Lambda 表達(dá)式可以有零個(gè)或多個(gè)參數(shù)乎折;

2绒疗,參數(shù)的類型既可以明確聲明,也可以根據(jù)上下文來推斷骂澄。例如:(int a)與(a)效果相同吓蘑。

3,參數(shù)需包含在圓括號(hào)內(nèi)坟冲,參數(shù)之間用逗號(hào)分隔磨镶。例如:(a, b) 或 (String a, String b) 或 (int a, String b, float c),空?qǐng)A括號(hào)代表參數(shù)集為空健提。例如:() -> 30琳猫;當(dāng)只有一個(gè)參數(shù),且其類型可推導(dǎo)時(shí)私痹,圓括號(hào)()可省略脐嫂。例如:a -> return a*a;

4侄榴,Lambda 表達(dá)式的主體({}內(nèi)的表達(dá)式)可包含零條或多條語句雹锣,如果 Lambda 表達(dá)式的主體只有一條語句,花括號(hào){}可省略癞蚕。如果 Lambda 表達(dá)式的主體包含一條以上語句蕊爵,則表達(dá)式必須包含在花括號(hào){}中。下面通過代碼來舉幾個(gè)簡單例子桦山。

1攒射,線程的初始化方法

//舊方法:

new Thread(new Runnable() {

@Override

public void run() {

? ? System.out.println("this thread");

}

}).start();

//新方法

new Thread(

() -> System.out.println("this thread")

).start();

2,List循環(huán)轉(zhuǎn)化為Lambda表達(dá)式

//老方法

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

for(Integer n: list) {

? System.out.println(n);

}

//新方法

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

list.forEach(n -> System.out.println(n));

或者

list.forEach(System.out::println);

3恒水,對(duì)象排序中比較器的實(shí)現(xiàn)

//老方法

Comparator<Developer> byName = new Comparator<Developer>() {

? ? @Override

? ? public int compare(Developer o1, Developer o2) {

? ? ? ? return o1.getName().compareTo(o2.getName());

? ? }

};

//新方法

Comparator<Developer> byName =

? ? ? ? (Developer o1, Developer o2)->o1.getName().compareTo(o2.getName());

二会放、Stream API

? ? ? ? Stream API作為 JDK8 的一大亮點(diǎn),它與 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念钉凌。它也不同于 StAX(Streaming API for XML) 對(duì) XML 解析的 Stream咧最,也不是Storm、Spark御雕、Flink等對(duì)大數(shù)據(jù)實(shí)時(shí)處理的 Stream矢沿。JDK8 中的 Stream 是對(duì)集合(Collection)對(duì)象功能的增強(qiáng),它專注于對(duì)集合對(duì)象進(jìn)行各種非常便利酸纲、高效的聚合操作(aggregate operation)捣鲸,或者大批量數(shù)據(jù)操作 (bulk data operation)。Stream API 借助于同樣新出現(xiàn)的 Lambda 表達(dá)式闽坡,極大的提高編程效率和程序可讀性栽惶。同時(shí)它提供串行和并行兩種模式進(jìn)行匯聚操作愁溜,并發(fā)模式能夠充分利用多核處理器的優(yōu)勢(shì),使用 fork/join 并行方式(JDK7引入)來拆分任務(wù)和加速處理過程外厂。通常編寫并行代碼很難而且容易出錯(cuò), 但使用 Stream API 無需編寫一行多線程的代碼冕象,就可以很方便地寫出高性能的并發(fā)程序。所以說酣衷,JDK8 中首次出現(xiàn)的 java.util.stream 是一個(gè)函數(shù)式語言+多核時(shí)代綜合影響的產(chǎn)物交惯。那JDK8中的Stream是什么次泽?Stream 不是集合元素穿仪,它不是數(shù)據(jù)結(jié)構(gòu)并不保存數(shù)據(jù),它是有關(guān)算法和計(jì)算的意荤,它更像一個(gè)高級(jí)版本的 Iterator啊片。原始版本的 Iterator,用戶只能顯式地一個(gè)一個(gè)遍歷元素并對(duì)其執(zhí)行某些操作玖像;高級(jí)版本的 Stream紫谷,用戶只要給出需要對(duì)其包含的元素執(zhí)行什么操作,比如 “過濾掉長度大于 10 的字符串”捐寥、“獲取每個(gè)字符串的首字母”等笤昨,Stream 會(huì)隱式地在內(nèi)部進(jìn)行遍歷,做出相應(yīng)的數(shù)據(jù)轉(zhuǎn)換握恳。Stream 就如同一個(gè)迭代器(Iterator)瞒窒,單向,不可往復(fù)乡洼,數(shù)據(jù)只能遍歷一次崇裁,遍歷過一次后即用盡了,就好比流水從面前流過束昵,一去不復(fù)返拔稳。而和迭代器又不同的是,Stream 可以并行化操作锹雏,迭代器只能命令式地巴比、串行化操作。顧名思義礁遵,當(dāng)使用串行方式去遍歷時(shí)轻绞,每個(gè) item 讀完后再讀下一個(gè) item。而使用并行去遍歷時(shí)榛丢,數(shù)據(jù)會(huì)被分成多個(gè)段铲球,其中每一個(gè)都在不同的線程中處理,然后將結(jié)果一起輸出晰赞。Stream 的并行操作依賴于 Fork/Join 框架來拆分任務(wù)和加速處理過程稼病。下面通過幾個(gè)實(shí)列來了解Stream API的用法选侨。

1,map/flatMap

//老方法

List<Integer> nums = Arrays.asList(1, 2, 3, 4);

List<Integer> squareNums=new ArrayList<>();

for(Integer num:nums)

{

squareNums.add(num*num);

}

//新方法

List<Integer> nums = Arrays.asList(1, 2, 3, 4);

List<Integer> squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());// map 生成的是個(gè)一對(duì)一映射然走,每個(gè)輸入元素援制,都按照規(guī)則轉(zhuǎn)換成為另外一個(gè)元素。還有一些場景芍瑞,是一對(duì)多映射關(guān)系的晨仑,這時(shí)可以使用 flatMap,有興趣的可以參見后文列舉的參考資料拆檬,這里不詳述洪己。

2,filter

//老方法

Integer[] sixNums = {1, 2, 3, 4, 5, 6};

List<Integer> evensList = new ArrayList<>();

for(Integer num:sixNums)

{if(num%2==0){evens.add(num);}

}

Integer[] evens= new Integer[evensList .size()];

evens = evensList .toArray(evens);

//新方法

Integer[] sixNums = {1, 2, 3, 4, 5, 6};

Integer[] evens =

Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new);

3竟贯,forEach

見前文Lambda表達(dá)式答捕。

4,findFirst

它總是返回 Stream 的第一個(gè)元素屑那,或者空拱镐。這里比較重點(diǎn)的是它的返回值類型:Optional,它可能含有某值持际,或者不包含沃琅。使用它的目的是盡可能避免NullPointerException。

如String strA = " abcd ", strB = null;要求求strA或者strB的長度蜘欲,即實(shí)現(xiàn)

getLength(String text)方法益眉。如下:

public static int getLength(String text) {

// 老方法

// return if (text != null) ? text.length() : -1;

//新方法

return Optional.ofNullable(text).map(String::length).orElse(-1);

};

5,limit/skip

limit 返回 Stream 的前面 n 個(gè)元素芒填;skip 則是扔掉前 n 個(gè)元素呜叫。代碼如下:

public void testLimitAndSkip() {

List<Person> persons = new ArrayList();

for (int i = 1; i <= 10000; i++) {

Person person = new Person(i, "name" + i);

persons.add(person);

}

List<String> personList2 = persons.stream().map(Person::getName).limit(10).skip(3).collect(Collectors.toList());

System.out.println(personList2);

}

private class Person {

public int no;

private String name;

public Person (int no, String name) {

this.no = no;

this.name = name;

}

public String getName() {

return name;

}

}

輸出結(jié)果:

[name4, name5, name6, name7, name8, name9, name10]

6,stored

對(duì) Stream 的排序通過 sorted 進(jìn)行殿衰,它比數(shù)組的排序更強(qiáng)之處在于你可以首先對(duì) Stream 進(jìn)行各類 map朱庆、filter、limit闷祥、skip 甚至 distinct 來減少元素?cái)?shù)量后娱颊,再排序,這能幫助程序明顯縮短執(zhí)行時(shí)間凯砍。

List<Person> persons = new ArrayList();

for (int i = 1; i <= 5; i++) {

Person person = new Person(i, "name" + i);

persons.add(person);

}

List<Person> personList2 = persons.stream().limit(2).sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList());

System.out.println(personList2);

7箱硕,Match

Stream 有三個(gè) match 方法,從語義上說:

allMatch:Stream 中全部元素符合傳入的 predicate悟衩,返回 true

anyMatch:Stream 中只要有一個(gè)元素符合傳入的 predicate剧罩,返回 true

noneMatch:Stream 中沒有一個(gè)元素符合傳入的 predicate,返回 true

它們都不是要遍歷全部元素才能返回結(jié)果座泳。例如 allMatch 只要一個(gè)元素不滿足條件惠昔,就 skip 剩下的所有元素幕与,返回 false。如:

List<Person> persons = new ArrayList();

persons.add(new Person(1, "name" + 1, 10));

persons.add(new Person(2, "name" + 2, 21));

persons.add(new Person(3, "name" + 3, 34));

persons.add(new Person(4, "name" + 4, 6));

persons.add(new Person(5, "name" + 5, 55));

boolean isAllAdult = persons.stream().

allMatch(p -> p.getAge() > 18);

System.out.println("All are adult? " + isAllAdult);

boolean isThereAnyChild = persons.stream().

anyMatch(p -> p.getAge() < 12);

System.out.println("Any child? " + isThereAnyChild);

輸出結(jié)果:

All are adult? false

Any child? true

? ? ? ? 本文是總結(jié)自己的工作實(shí)戰(zhàn)镇防,拋磚引玉啦鸣,列舉了常見的JDK8 Lambda表達(dá)式和Stream API。如果想深入了解JDK8的特性来氧,可以參看Oracle和IBM官網(wǎng)資料诫给。

1,https://www.oracle.com/technetwork/articles/java/architect-lambdas-part1-2080972.html

2啦扬,https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末中狂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子考传,更是在濱河造成了極大的恐慌吃型,老刑警劉巖证鸥,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件僚楞,死亡現(xiàn)場離奇詭異,居然都是意外死亡枉层,警方通過查閱死者的電腦和手機(jī)泉褐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸟蜡,“玉大人膜赃,你說我怎么就攤上這事∪嗤” “怎么了跳座?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泣矛。 經(jīng)常有香客問我疲眷,道長,這世上最難降的妖魔是什么您朽? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任狂丝,我火速辦了婚禮,結(jié)果婚禮上哗总,老公的妹妹穿的比我還像新娘几颜。我一直安慰自己,他們只是感情好讯屈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布蛋哭。 她就那樣靜靜地躺著,像睡著了一般涮母。 火紅的嫁衣襯著肌膚如雪谆趾。 梳的紋絲不亂的頭發(fā)上准颓,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音棺妓,去河邊找鬼攘已。 笑死,一個(gè)胖子當(dāng)著我的面吹牛怜跑,可吹牛的內(nèi)容都是我干的样勃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼性芬,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼峡眶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起植锉,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤辫樱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后俊庇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狮暑,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年辉饱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搬男。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彭沼,死狀恐怖缔逛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姓惑,我是刑警寧澤褐奴,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站于毙,受9級(jí)特大地震影響敦冬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜望众,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一匪补、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烂翰,春花似錦夯缺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至佳恬,卻和暖如春捏境,著一層夾襖步出監(jiān)牢的瞬間于游,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國打工垫言, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贰剥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓筷频,卻偏偏與公主長得像蚌成,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凛捏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容