1. 新時(shí)代的Java語言
新時(shí)代的Java是以JDK8的發(fā)布為分水嶺树瞭,從JDK8開始,Java開發(fā)進(jìn)入一個(gè)新的階段典徊,Java8 經(jīng)歷9個(gè)里程碑版本颤专,于2014年3月18日正式發(fā)布,距今已有很長一段時(shí)間了逮光,一些流行框架都采用了Java8代箭,比如Mybatis3.5.x開始全面采用JDK8,Spring5.x開始全面采用JDK8涕刚,SpringBoot2.x開始全面采用JDK8嗡综,Spring Cloud F版開始也要求至少JDK8;
2. Java8有哪些新特性副女?
1蛤高、Lambda表達(dá)式蚣旱;
2、方法引用戴陡;
3塞绿、默認(rèn)方法;
4恤批、可重復(fù)注解异吻;
5、類型注解喜庞;
6诀浪、改進(jìn)的類型推斷;
7延都、方法參數(shù)反射雷猪;
8、Stream API晰房;
9求摇、Security增強(qiáng);
10殊者、JavaFX增強(qiáng)与境;
11、Tool增強(qiáng)猖吴;
12摔刁、國際化增強(qiáng);
13海蔽、Deployment增強(qiáng)共屈;
14、date-time日期包党窜;
15趁俊、Nashorn javascript引擎;
16刑然、Pack200壓縮工具寺擂;
17、IO and NIO增強(qiáng)泼掠;
18怔软、java.lang and java.util 包增強(qiáng);
19择镇、JDBC 4.2增強(qiáng)挡逼;
20、Java DB腻豌;
21家坎、java.net包增強(qiáng)嘱能;
22、java.util.concurrent包增強(qiáng)虱疏;
23惹骂、Java XML - JAXP;
24做瞪、HotSpot增強(qiáng)对粪;
25、Java Mission Control装蓬;
在Java8中最重要的兩個(gè)新特性就要數(shù)Lambda表達(dá)式和Stream API了著拭;
3. Stream API
Stream是Java 8中引入的全新API,位于java.util.stream包下牍帚,它與java.io 包下的 InputStream 和 OutputStream 等輸入輸出流是完全不同的概念儡遮;
Java 8 中的 Stream 是對數(shù)組、集合(Collection)功能的增強(qiáng)暗赶,它專注于對集合對象進(jìn)行各種非常便利且高效的操作峦萎,它的底層實(shí)現(xiàn)使用了并行化操作,利用Java7 中引入的 Fork/Join 框架來拆分任務(wù)忆首,加速處理過程,充分利用了現(xiàn)在多核處理器的優(yōu)勢被环;
需要強(qiáng)調(diào)的是Stream不對任何數(shù)據(jù)進(jìn)行存儲糙及,所以Stream也不是數(shù)據(jù)結(jié)構(gòu),Stream實(shí)現(xiàn)的是快速地對集合類的數(shù)據(jù)源進(jìn)行操作(如:過濾筛欢,排序浸锨、求和等等);
Stream
IntStream
DoubleStream
LongStream
Stream出現(xiàn)之前版姑,遍歷一個(gè)集合List柱搜、Array最傳統(tǒng)的做法大概是用Iterator,或者 for 循環(huán)剥险,這種兩種方式都屬于外部迭代聪蘸,然而外部迭代存在著一些問題;
1表制、開發(fā)人員需要自己手寫迭代的邏輯健爬,大部分場景迭代邏輯都是每個(gè)元素遍歷一次;
2么介、如果存在像排序娜遵、求最小值、求最大值這樣的有狀態(tài)的中間操作壤短,不得不進(jìn)行多次迭代设拟;
Stream 處理數(shù)據(jù)的過程可以類別成工廠的流水線慨仿,數(shù)據(jù)可以看做流水線上的原料,對數(shù)據(jù)的操作可以看做流水線上的工人對原料的操作纳胧;
事實(shí)上Stream 只是一個(gè)接口镰吆,并沒有操作的缺省實(shí)現(xiàn),最主要的實(shí)現(xiàn)是
ReferencePipeline躲雅,而 ReferencePipeline 繼承自AbstractPipeline鼎姊,AbstractPipeline實(shí)現(xiàn)了BaseStream 接口并實(shí)現(xiàn)了它的方法,但ReferencePipeline 仍然是一個(gè)抽象類相赁,因?yàn)樗]有實(shí)現(xiàn)所有的抽象方法相寇,比如 AbstractPipeline 中的 opWrapSink,ReferencePipeline內(nèi)部定義了三個(gè)靜態(tài)內(nèi)部類钮科,分別是:Head, StatelessOp, StatefulOp唤衫,但只有 Head 不再是抽象類;
ReferencePipeline 包含了控制數(shù)據(jù)流入的 Head绵脯,中間操作 StatelessOp, StatefulOp佳励,終止操作 TerminalOp;
Stream的工作流程
在Java 8中蛆挫,Stream的生命周期一共有三個(gè)階段:
1.獲取數(shù)據(jù)源并創(chuàng)建Stream實(shí)例赃承,數(shù)據(jù)源可以是數(shù)組、列表悴侵、對象或者I/O流瞧剖;
2.執(zhí)行中間操作(Intermediate Operations),中間操作可以是過濾可免、排序抓于、類型轉(zhuǎn)換等操作;
3.執(zhí)行末端操作(Terminal Operation)浇借,末端操作主要是對最終結(jié)果進(jìn)行計(jì)數(shù)捉撮、求和、創(chuàng)建新集合等操作妇垢;
Stream的操作大部分都是鏈?zhǔn)讲僮鳎?/p>
如何創(chuàng)建Stream實(shí)例巾遭?
1.使用數(shù)組創(chuàng)建Stream
2.使用List集合創(chuàng)建Stream
3.使用Builder方法創(chuàng)建Stream
參看代碼演示;
Stream 常用的流操作包括:
中間操作(Intermediate Operations)
Stream的中間操作將返回一個(gè)Stream,它允許開發(fā)者以查詢的方式調(diào)用多個(gè)其他的操作闯估。特別注意的是恢总,在“終端操作”方法未被調(diào)用之前,“中間操作”的方法不會被執(zhí)行睬愤;
無狀態(tài)(Stateless)操作:每個(gè)數(shù)據(jù)的處理是獨(dú)立的片仿,不會影響或依賴之前的數(shù)據(jù)。如filter()尤辱、flatMap()砂豌、flatMapToDouble()厢岂、flatMapToInt()、flatMapToLong()阳距、map()塔粒、mapToDouble()、mapToInt()筐摘、mapToLong()卒茬、peek()、unordered() 等咖熟;
有狀態(tài)(Stateful)操作:處理時(shí)會記錄狀態(tài)圃酵,比如處理了幾個(gè)。后面元素的處理會依賴前面記錄的狀態(tài)馍管,或者拿到所有元素才能繼續(xù)下去郭赐,如
distinct()、sorted()确沸、sorted(comparator)捌锭、limit()、skip() 等罗捎;
終止操作(Terminal Operations)
非短路操作:處理完所有數(shù)據(jù)才能得到結(jié)果观谦,如
collect()、count()桨菜、forEach()豁状、forEachOrdered()、max()雷激、min()、reduce()告私、toArray()等屎暇;
短路(short-circuiting)操作:拿到符合預(yù)期的結(jié)果就會停下來,不一定會處理完所有數(shù)據(jù)驻粟。如anyMatch()根悼、allMatch()、noneMatch()蜀撑、findFirst()挤巡、findAny() 等;
Parallel Streams
streams可以是串行或者并行的酷麦;
在串行streams上的操作是在一個(gè)單線程中完成的矿卑,而并行streams上的操作是在多個(gè)線程上并發(fā)完成的;
使用并行stream可以充分利用多核處理器的優(yōu)勢沃饶,提升速度和性能母廷,而所需要做的僅僅是將stream() 改為 parallelStream()即可轻黑;
為什么要使用Stream?
在命令式編程中,我們必須逐行編寫代碼琴昆,才能完成相關(guān)的計(jì)算氓鄙,例如,計(jì)算1~10000的數(shù)的總和业舍,我們需要使用for(int i=1;i<=10000;i++){….}循環(huán)語句來迭代求值抖拦,在這個(gè)語句中,我們需要花費(fèi)額外的精力來維護(hù)loop變量的值舷暮,而在聲明式編程中态罪,我們只需要關(guān)注想要實(shí)現(xiàn)的目標(biāo),而不是其內(nèi)部重復(fù)的循環(huán)邏輯脚牍;