這篇文章主要講解了Java8新特性Stream的詳細(xì)解析,內(nèi)容清晰明了,對此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會(huì)有幫助。
成都創(chuàng)新互聯(lián)專注于青山湖網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供青山湖營銷型網(wǎng)站建設(shè),青山湖網(wǎng)站制作、青山湖網(wǎng)頁設(shè)計(jì)、青山湖網(wǎng)站官網(wǎng)定制、微信小程序定制開發(fā)服務(wù),打造青山湖網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供青山湖網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
什么是Stream
Stream是Java 1.8版本開始提供的一個(gè)接口,主要提供對數(shù)據(jù)集合使用流的方式進(jìn)行操作,流中的元素不可變且只會(huì)被消費(fèi)一次,所有方法都設(shè)計(jì)成支持鏈?zhǔn)秸{(diào)用。使用Stream API可以極大生產(chǎn)力,寫出高效率、干凈、簡潔的代碼。
如何獲得Stream實(shí)例
Stream提供了靜態(tài)構(gòu)建方法,可以基于不同的參數(shù)創(chuàng)建返回Stream實(shí)例
使用Collection的子類實(shí)例調(diào)用stream()或者parallelStream()方法也可以得到Stream實(shí)例,兩個(gè)方法的區(qū)別在于后續(xù)執(zhí)行Stream其他方法的時(shí)候是單線程還是多線程
StreamstringStream = Stream.of("1", "2", "3"); //無限長的偶數(shù)流 Stream evenNumStream = Stream.iterate(0, n -> n + 2); List strList = new ArrayList<>(); strList.add("1"); strList.add("2"); strList.add("3"); Stream strStream = strList.stream(); Stream strParallelStream = strList.parallelStream();
filter
filter方法用于根據(jù)指定的條件做過濾,返回符合條件的流
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //獲得只包含正數(shù)的流,positiveNumStream -> (1,2,3) Stream positiveNumStream = numStream.filter(num -> num > 0);
map
map方法用于將流中的每個(gè)元素執(zhí)行指定的轉(zhuǎn)換邏輯,返回其他類型元素的流
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //轉(zhuǎn)換成字符串流 Stream strStream = numStream.map(String::valueOf);
mapToInt mapToLong mapToDouble
這三個(gè)方法是對map方法的封裝,返回的是官方為各個(gè)類型單獨(dú)定義的Stream,該Stream還提供了適合各自類型的其他操作方法
StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); IntStream intStream = stringStream.mapToInt(Integer::parseInt); LongStream longStream = stringStream.mapToLong(Long::parseLong); DoubleStream doubleStream = stringStream.mapToDouble(Double::parseDouble);
flatMap
flatMap方法用于將流中的每個(gè)元素轉(zhuǎn)換成其他類型元素的流,比如,當(dāng)前有一個(gè)訂單(Order)列表,每個(gè)訂單又包含多個(gè)商品(itemList),如果要得到所有訂單的所有商品匯總,就可以使用該方法,如下:
Stream- allItemStream = orderList.stream().flatMap(order -> order.itemList.stream());
flatMapToInt flatMapToLong flatMapToDouble
這三個(gè)方法是對flatMap方法的封裝,返回的是官方為各個(gè)類型單獨(dú)定義的Stream,使用方法同上
distinct
distinct方法用于對流中的元素去重,判斷元素是否重復(fù)使用的是equals方法
StreamnumStream = Stream.of(-2, -1, 0, 0, 1, 2, 2, 3); //不重復(fù)的數(shù)字流,uniqueNumStream -> (-2, -1, 0, 1, 2, 3) Stream uniqueNumStream = numStream.distinct();
sorted
sorted有一個(gè)無參和一個(gè)有參的方法,用于對流中的元素進(jìn)行排序。無參方法要求流中的元素必須實(shí)現(xiàn)Comparable接口,不然會(huì)報(bào)java.lang.ClassCastException異常
StreamunorderedStream = Stream.of(5, 6, 32, 7, 27, 4); //按從小到大排序完成的流,orderedStream -> (4, 5, 6, 7, 27, 32) Stream orderedStream = unorderedStream.sorted();
有參方法sorted(Comparator<? super T> comparator)不需要元素實(shí)現(xiàn)Comparable接口,通過指定的元素比較器對流內(nèi)的元素進(jìn)行排序
StreamunorderedStream = Stream.of("1234", "123", "12", "12345", "123456", "1"); //按字符串長度從小到大排序完成的流,orderedStream -> ("1", "12", "123", "1234", "12345", "123456") Stream orderedStream = unorderedStream.sorted(Comparator.comparingInt(String::length));
peek
peek方法可以不調(diào)整元素順序和數(shù)量的情況下消費(fèi)每一個(gè)元素,然后產(chǎn)生新的流,按文檔上的說明,主要是用于對流執(zhí)行的中間過程做debug的時(shí)候使用,因?yàn)镾tream使用的時(shí)候一般都是鏈?zhǔn)秸{(diào)用的,所以可能會(huì)執(zhí)行多次流操作,如果想看每個(gè)元素在多次流操作中間的流轉(zhuǎn)情況,就可以使用這個(gè)方法實(shí)現(xiàn)
Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList()); 輸出: Filtered value: three Mapped value: THREE Filtered value: four Mapped value: FOUR
limit(long maxSize)
limit方法會(huì)對流進(jìn)行順序截取,從第1個(gè)元素開始,保留最多maxSize個(gè)元素
StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //截取前3個(gè)元素,subStringStream -> ("-2", "-1", "0") Stream subStringStream = stringStream.limit(3);
skip(long n)
skip方法用于跳過前n個(gè)元素,如果流中的元素?cái)?shù)量不足n,則返回一個(gè)空的流
StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //跳過前3個(gè)元素,subStringStream -> ("1", "2", "3") Stream subStringStream = stringStream.skip(3);
forEach
forEach方法的作用跟普通的for循環(huán)類似,不過這個(gè)可以支持多線程遍歷,但是不保證遍歷的順序
StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //單線程遍歷輸出元素 stringStream.forEach(System.out::println); //多線程遍歷輸出元素 stringStream.parallel().forEach(System.out::println);
forEachOrdered
forEachOrdered方法可以保證順序遍歷,比如這個(gè)流是從外部傳進(jìn)來的,然后在這之前調(diào)用過parallel方法開啟了多線程執(zhí)行,就可以使用這個(gè)方法保證單線程順序遍歷
StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //順序遍歷輸出元素 stringStream.forEachOrdered(System.out::println); //多線程遍歷輸出元素,下面這行跟上面的執(zhí)行結(jié)果是一樣的 //stringStream.parallel().forEachOrdered(System.out::println);
toArray
toArray有一個(gè)無參和一個(gè)有參的方法,無參方法用于把流中的元素轉(zhuǎn)換成Object數(shù)組
StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); Object[] objArray = stringStream.toArray();
有參方法toArray(IntFunction generator)支持把流中的元素轉(zhuǎn)換成指定類型的元素?cái)?shù)組
StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); String[] strArray = stringStream.toArray(String[]::new);
reduce
reduce有三個(gè)重載方法,作用是對流內(nèi)元素做累進(jìn)操作
第一個(gè)reduce(BinaryOperator
accumulator 為累進(jìn)操作的具體計(jì)算
單線程等下如下代碼
boolean foundAny = false; T result = null; for (T element : this stream) { if (!foundAny) { foundAny = true; result = element; } else result = accumulator.apply(result, element); } return foundAny ? Optional.of(result) : Optional.empty();
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //查找最小值 Optional min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo)); //輸出 -2 System.out.println(min.get()); //過濾出大于5的元素流 numStream = Stream.of(-2, -1, 0, 1, 2, 3).filter(num -> num > 5); //查找最小值 min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo)); //輸出 Optional.empty System.out.println(min);
第二個(gè)reduce(T identity, BinaryOperator
identity 為累進(jìn)操作的初始值
accumulator 同上
單線程等價(jià)如下代碼
T result = identity; for (T element : this stream) result = accumulator.apply(result, element) return result;
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //累加計(jì)算所有元素的和,sum=3 int sum = numStream.reduce(0, Integer::sum);
第三個(gè)reduce(U identity, BiFunction accumulator, BinaryOperator combiner)
identity和accumulator同上
combiner用于多線程執(zhí)行的情況下合并最終結(jié)果
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); int sum = numStream.parallel().reduce(0, (a, b) -> { System.out.println("accumulator執(zhí)行:" + a + " + " + b); return a + b; }, (a, b) -> { System.out.println("combiner執(zhí)行:" + a + " + " + b); return a + b; }); System.out.println("最終結(jié)果:"+sum); 輸出: accumulator執(zhí)行:0 + -1 accumulator執(zhí)行:0 + 1 accumulator執(zhí)行:0 + 0 accumulator執(zhí)行:0 + 2 accumulator執(zhí)行:0 + -2 accumulator執(zhí)行:0 + 3 combiner執(zhí)行:2 + 3 combiner執(zhí)行:-1 + 0 combiner執(zhí)行:1 + 5 combiner執(zhí)行:-2 + -1 combiner執(zhí)行:-3 + 6 最終結(jié)果:3
collect
collect有兩個(gè)重載方法,主要作用是把流中的元素作為集合轉(zhuǎn)換成其他Collection的子類,其內(nèi)部實(shí)現(xiàn)類似于前面的累進(jìn)操作
第一個(gè)collect(Supplier
supplier 需要返回開始執(zhí)行時(shí)的默認(rèn)結(jié)果
accumulator 用于累進(jìn)計(jì)算用
combiner 用于多線程合并結(jié)果
單線程執(zhí)行等價(jià)于如下代碼
R result = supplier.get(); for (T element : this stream) accumulator.accept(result, element); return result;
第二個(gè)collect(Collector<? super T, A, R> collector)
collector其實(shí)是對上面的方法參數(shù)的一個(gè)封裝,內(nèi)部執(zhí)行邏輯是一樣的,只不過JDK提供了一些默認(rèn)的Collector實(shí)現(xiàn)
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); List numList = numStream.collect(Collectors.toList()); Set numSet = numStream.collect(Collectors.toSet());
min
min方法用于計(jì)算流內(nèi)元素的最小值
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional min = numStream.min(Integer::compareTo);
max
min方法用于計(jì)算流內(nèi)元素的最大值
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional max = numStream.max(Integer::compareTo);
count
count方法用于統(tǒng)計(jì)流內(nèi)元素的總個(gè)數(shù)
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //count=6 long count = numStream.count();
anyMatch
anyMatch方法用于匹配校驗(yàn)流內(nèi)元素是否有符合指定條件的元素
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //判斷是否包含正數(shù),hasPositiveNum=true boolean hasPositiveNum = numStream.anyMatch(num -> num > 0);
allMatch
allMatch方法用于匹配校驗(yàn)流內(nèi)元素是否所有元素都符合指定條件
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //判斷是否全部是正數(shù),allNumPositive=false boolean allNumPositive = numStream.allMatch(num -> num > 0);
noneMatch
noneMatch方法用于匹配校驗(yàn)流內(nèi)元素是否都不符合指定條件
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //判斷是否沒有小于0的元素,noNegativeNum=false boolean noNegativeNum = numStream.noneMatch(num -> num < 0);
findFirst
findFirst方法用于獲取第一個(gè)元素,如果流是空的,則返回Optional.empty
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //獲取第一個(gè)元素,firstNum=-2 Optional firstNum = numStream.findFirst();
findAny
findAny方法用于獲取流中的任意一個(gè)元素,如果流是空的,則返回Optional.empty,因?yàn)榭赡軙?huì)使用多線程,所以不保證每次返回的是同一個(gè)元素
StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional anyNum = numStream.findAny();
看完上述內(nèi)容,是不是對Java8新特性Stream的詳細(xì)解析有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。