您好,登錄后才能下訂單哦!
隨著Java的發(fā)展,越來越多的企業(yè)開始使用JDK1.8 版本。JDK1.8 是自 JDK1.5之后最重要的版本,這個版本包含語言、編譯器、庫、工具、JVM等方面的十多個新特性。本次文章將著重學習Stream。
Stream 是JDK1.8 中處理集合的關(guān)鍵抽象概念,Lambda 和 Stream 是JDK1.8新增的函數(shù)式編程最有亮點的特性了,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復雜的查找、過濾和映射數(shù)據(jù)等操作。使用Stream API 對集合數(shù)據(jù)進行操作,就類似于使用SQL執(zhí)行的數(shù)據(jù)庫查詢。Stream 使用一種類似用 SQL 語句從數(shù)據(jù)庫查詢數(shù)據(jù)的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。Stream API可以極大提高Java程序員的生產(chǎn)力,讓程序員寫出高效率、干凈、簡潔的代碼。
這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 并且可以在管道的節(jié)點上進行處理, 比如篩選, 排序,聚合等。
元素流在管道中經(jīng)過中間操作(intermediate operation)的處理,最后由最終操作(terminal operation)得到前面處理的結(jié)果。
+--------------------+ +------+ +------+ +---+ +-------+ | stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect| +--------------------+ +------+ +------+ +---+ +-------+
簡而言之,Stream API提供了一種高效且易于使用的處理數(shù)據(jù)的方式。
1.Stream(流)是一個來自數(shù)據(jù)源的元素隊列并支持聚合操作。
2.和以前的Collection操作不同, Stream操作還有兩個基礎(chǔ)的特征:
特點:
1.Stream 不是數(shù)據(jù)結(jié)構(gòu),不會保存數(shù)據(jù)。
2.Stream 不會修改原來的數(shù)據(jù)源,它會將操作后的數(shù)據(jù)保存到另外一個對象中。(保留意見:畢竟peek方法可以修改流中元素)
3.惰性求值,流在中間處理過程中,只是對操作進行了記錄,并不會立即執(zhí)行,需要等到執(zhí)行終止操作的時候才會進行實際的計算。
Stream 操作分為中間操作或者終止操作兩種,終止操作返回一特定類型的計算結(jié)果,而中間操作返回Stream本身,Stream 的操作類型具體分類如下:
解釋:
使用Stream流分為三步。
創(chuàng)建Stream
一個數(shù)據(jù)源(如:集合、數(shù)組),獲取一個Stream流。
中間操作
一個中間操作鏈,對數(shù)據(jù)源(如:集合、數(shù)組)的數(shù)據(jù)進行處理。
終止操作
一個終止操作,執(zhí)行中間操作鏈,并產(chǎn)生一個計算結(jié)果。
中間操作
filter: 過濾流,過濾流中的元素,返回一個符合條件的Stream
map: 轉(zhuǎn)換流,將一種類型的流轉(zhuǎn)換為另外一種流。(mapToInt、mapToLong、mapToDouble 返回int、long、double基本類型對應(yīng)的Stream)
flatMap:簡單的說,就是一個或多個流合并成一個新流。(flatMapToInt、flatMapToLong、flatMapToDouble 返回對應(yīng)的IntStream、LongStream、DoubleStream流。)
distinct: 返回去重的Stream。
sorted: 返回一個排序的Stream。
peek: 主要用來查看流中元素的數(shù)據(jù)狀態(tài)。
limit: 返回前n個元素數(shù)據(jù)組成的Stream。屬于短路操作
skip: 返回第n個元素后面數(shù)據(jù)組成的Stream。
結(jié)束操作
forEach: 循環(huán)操作Stream中數(shù)據(jù)。
toArray: 返回流中元素對應(yīng)的數(shù)組對象。
reduce: 聚合操作,用來做統(tǒng)計。
collect: 聚合操作,封裝目標數(shù)據(jù)。
min、max、count: 聚合操作,最小值,最大值,總數(shù)量。
anyMatch: 短路操作,有一個符合條件返回true。
allMatch: 所有數(shù)據(jù)都符合條件返回true。
noneMatch: 所有數(shù)據(jù)都不符合條件返回true。
findFirst: 短路操作,獲取第一個元素。
findAny: 短路操作,獲取任一元素。
forEachOrdered: 暗元素順序執(zhí)行循環(huán)操作。
在 Java 8 中, 集合接口有兩個方法來生成流:
/** * stream,獲取各種集合的stream流 */ @Test public void testCollectionStream(){ //List集合 List<String> stringList = new ArrayList<>(); //Set集合 Set<String> stringSet = new HashSet<>(); //Map集合 Map<String,Object> stringObjectMap = new HashMap<>(); //數(shù)組 String[] stringArray = {"張三三","李四","王五","王五","趙八",}; //通過list獲取stream流 Stream<String> streamList = stringList.stream(); //通過set獲取stream流 Stream<String> streamSet = stringSet.stream(); //通過map獲取stream流 Stream<String> streamMap = stringObjectMap.keySet().stream(); //通過array獲取stream流 Stream<String> streamArray1 = Stream.of(stringArray); }
@Test public void testCollectionStream(){ // 1. Individual values Stream stream = Stream.of("a", "b", "c"); // 2. Arrays String[] strArray = new String[]{"a", "b", "c"}; stream = Stream.of(strArray); stream = Arrays.stream(strArray); // 3. Collections List<String> list = Arrays.asList(strArray); stream = list.stream(); }
關(guān)于Stream的常見操作方式,主要分為兩大類: 中間操作和終止操作 ,接下來就通過這兩大分類,講解下具體的語法用法。
1.1 篩選過濾
filter:過濾流中的某些元素
/** * filter 方法 , 返回符合過濾條件的值 */ @Test public void testFilter() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.stream().filter(e -> e.contains("張")).forEach(System.out::println); }
或
filter多個過濾篩選條件
/** * list集合stream流式操作 */ @Test public void testStreamList() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.stream().filter(e -> e.startsWith("張")) //過濾所有姓張的人 .filter(e -> e.length() == 3) //過濾所有姓名是3個字的人 .forEach(System.out::println); //遍歷打印,System.out::println表明System.out調(diào)用println打印方法 }
limit(n):獲取前n個元素
/** * limit 方法 ,返回前n個元素數(shù)據(jù)值組成的Stream。 */ @Test public void testLimit() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); list.stream().limit(3).forEach(System.out::println); //取前3個 }
skip(n):跳過n元素,配合limit(n)可實現(xiàn)分頁
/** * skip方法 ,跳過前n個元素的中間流操作,返回剩下的值。 */ @Test public void testSkip() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); //list.stream().skip(3).forEach(System.out::println); //跳過前3個 list.stream().skip(3).limit(2).forEach(System.out::println); //skip+limit實現(xiàn)分頁 }
distinct:通過流中元素的 hashCode() 和 equals() 去除重復元素
/** * distinct, 返回去重的Stream */ @Test public void testDistinct() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); list.stream().distinct().collect(Collectors.toList()).forEach(System.out::println); }
1.2 排序
sorted():自然排序,流中元素需實現(xiàn)Comparable接口
/** * sorted: 返回一個排序的Stream */ @Test public void testSorted() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); list.stream().distinct().sorted().collect(Collectors.toList()).forEach(System.out::println); }
sorted(Comparator com):定制排序,自定義Comparator排序器
1.3 映射
map:接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,并將其映射成一個新的元素。
/** * 遍歷map集合,截取substring(2)開始的值 */ @Test public void testMap() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); Stream<String> stream = list.stream().map(e -> e.substring(2)); stream.forEach(System.out::println); }
forEach:ForEach流式遍歷集合
/** * forEach, ForEach流式遍歷list集合 */ @Test public void testForEach() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.stream().forEach(System.out::println); }
2.1 匹配、聚合操作
allMatch:接收一個 Predicate 函數(shù),當流中每個元素都符合該斷言時才返回true,否則返回false
/** * allMatch:接收一個 Predicate 函數(shù),當流中每個元素都符合該斷言時才返回true,否則返回false */ @Test public void testAllMatch() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); boolean b = list.stream() .allMatch(e -> list.size() > 8); System.out.println("b = " + b); }
noneMatch:接收一個 Predicate 函數(shù),當流中每個元素都不符合該斷言時才返回true,否則返回false
/** * noneMatch: 接收一個 Predicate 函數(shù),當流中每個元素都不符合該斷言時才返回true,否則返回false */ @Test public void testNoneMatch() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); boolean b = list.stream().noneMatch(e->e.equals("張三")); System.out.println("b = " + b); }
anyMatch:接收一個 Predicate 函數(shù),只要流中有一個元素滿足該斷言則返回true,否則返回false
/** * anyMatch:接收一個 Predicate 函數(shù),只要流中有一個元素滿足該斷言則返回true,否則返回false */ @Test public void testAnyMatch() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); boolean b = list.stream().anyMatch(e -> e.equals("王二麻子")); System.out.println("b = " + b); }
findFirst:返回流中第一個元素
/** * findFirst:返回流中第一個元素 */ @Test public void testFindFirsth() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); Optional<String> first = list.stream().findFirst(); System.out.println("first = " + first.get()); }
findAny:返回流中的任意元素
/** * findAny:返回流中第一個元素 */ @Test public void testFindAny() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); Optional<String> any = list.stream().findAny(); System.out.println("any = " + any.get()); }
count:返回流中元素的總個數(shù)
/** * count,獲取List集合的長度 */ @Test public void testCount() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); long count = list.stream().count(); System.out.println("count = " + count); int size = list.size(); System.out.println("size = " + size); }
2.2 Collector 工具庫:Collectors
Collectors
Student s1 = new Student("aa", 10,1); Student s2 = new Student("bb", 20,2); Student s3 = new Student("cc", 10,3); List<Student> list = Arrays.asList(s1, s2, s3); //裝成list List<Integer> ageList = list.stream().map(Student::getAge).collect(Collectors.toList()); // [10, 20, 10] //轉(zhuǎn)成set Set<Integer> ageSet = list.stream().map(Student::getAge).collect(Collectors.toSet()); // [20, 10] //轉(zhuǎn)成map,注:key不能相同,否則報錯 Map<String, Integer> studentMap = list.stream().collect(Collectors.toMap(Student::getName, Student::getAge)); // {cc=10, bb=20, aa=10} //字符串分隔符連接 String joinName = list.stream().map(Student::getName).collect(Collectors.joining(",", "(", ")")); // (aa,bb,cc) //聚合操作 //1.學生總數(shù) Long count = list.stream().collect(Collectors.counting()); // 3 //2.最大年齡 (最小的minBy同理) Integer maxAge = list.stream().map(Student::getAge).collect(Collectors.maxBy(Integer::compare)).get(); // 20 //3.所有人的年齡 Integer sumAge = list.stream().collect(Collectors.summingInt(Student::getAge)); // 40 //4.平均年齡 Double averageAge = list.stream().collect(Collectors.averagingDouble(Student::getAge)); // 13.333333333333334 // 帶上以上所有方法 DoubleSummaryStatistics statistics = list.stream().collect(Collectors.summarizingDouble(Student::getAge)); System.out.println("count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage()); //分組 Map<Integer, List<Student>> ageMap = list.stream().collect(Collectors.groupingBy(Student::getAge)); //多重分組,先根據(jù)類型分再根據(jù)年齡分 Map<Integer, Map<Integer, List<Student>>> typeAgeMap = list.stream().collect(Collectors.groupingBy(Student::getType, Collectors.groupingBy(Student::getAge))); //分區(qū) //分成兩部分,一部分大于10歲,一部分小于等于10歲 Map<Boolean, List<Student>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 10)); //規(guī)約 Integer allAge = list.stream().map(Student::getAge).collect(Collectors.reducing(Integer::sum)).get(); //40
為了方便小伙伴們看到這篇博客時,學習的更加輕松,這里貼出源碼,小伙伴們學習是可貼到IDEA運行查看Stream過濾篩選的結(jié)果,以此對Stream的流式操作更加熟悉。
package com.java8.example.chapter3; import org.junit.jupiter.api.Test; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @desc: Stream流式操作 * @author: cao_wencao * @date: 2020-09-17 15:24 */ public class TestStreamList { /** * list集合stream流式操作 */ @Test public void testStreamList() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.stream().filter(e -> e.startsWith("張")) //過濾所有姓張的人 .filter(e -> e.length() == 3) //過濾所有姓名是3個字的人 .forEach(System.out::println); //遍歷打印,System.out::println表明System.out調(diào)用println打印方法 } /** * stream,獲取各種集合的stream流 */ @Test public void testCollectionStream() { List<String> stringList = new ArrayList<>(); Set<String> stringSet = new HashSet<>(); Map<String, Object> stringObjectMap = new HashMap<>(); String[] stringArray = {"張三三", "李四", "王五", "王五", "趙八",}; //通過list獲取stream流 Stream<String> streamList = stringList.stream(); //通過set獲取stream流 Stream<String> streamSet = stringSet.stream(); //通過map獲取stream流 Stream<String> streamMap = stringObjectMap.keySet().stream(); //通過array獲取stream流 Stream<String> streamArray1 = Stream.of(stringArray); } /** * forEach, ForEach流式遍歷list集合 */ @Test public void testForEach() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.stream().forEach(System.out::println); } /** * filter 方法 , 返回符合過濾條件的值 */ @Test public void testFilter() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.stream().filter(e -> e.contains("張")).forEach(System.out::println); } /** * 遍歷map集合,截取substring(2)開始的值 */ @Test public void testMap() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); Stream<String> stream = list.stream().map(e -> e.substring(2)); stream.forEach(System.out::println); } /** * count,獲取List集合的長度 */ @Test public void testCount() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); long count = list.stream().count(); System.out.println("count = " + count); int size = list.size(); System.out.println("size = " + size); } /** * limit 方法 ,返回前n個元素數(shù)據(jù)值組成的Stream。 */ @Test public void testLimit() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); list.stream().limit(3).forEach(System.out::println); //取前3個 } /** * skip方法 ,跳過前n個元素的中間流操作,返回剩下的值。 */ @Test public void testSkip() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); //list.stream().skip(3).forEach(System.out::println); //跳過前3個 list.stream().skip(3).limit(2).forEach(System.out::println); //skip+limit實現(xiàn)分頁 } /** * collect,將流轉(zhuǎn)化為集合 */ @Test public void testCollect() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); List<String> collect = list.stream().skip(3).limit(2).collect(Collectors.toList()); collect.forEach(System.out::println); } /** * distinct, 返回去重的Stream */ @Test public void testDistinct() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); list.stream().distinct().collect(Collectors.toList()).forEach(System.out::println); } /** * sorted: 返回一個排序的Stream */ @Test public void testSorted() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); list.stream().distinct().sorted().collect(Collectors.toList()).forEach(System.out::println); } /** * anyMatch:接收一個 Predicate 函數(shù),只要流中有一個元素滿足該斷言則返回true,否則返回false */ @Test public void testAnyMatch() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); boolean b = list.stream().anyMatch(e -> e.equals("王二麻子")); System.out.println("b = " + b); } /** * noneMatch: 接收一個 Predicate 函數(shù),當流中每個元素都不符合該斷言時才返回true,否則返回false */ @Test public void testNoneMatch() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); boolean b = list.stream().noneMatch(e->e.equals("張三")); System.out.println("b = " + b); } /** * allMatch:接收一個 Predicate 函數(shù),當流中每個元素都符合該斷言時才返回true,否則返回false */ @Test public void testAllMatch() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); boolean b = list.stream() .allMatch(e -> list.size() > 8); System.out.println("b = " + b); } /** * findFirst:返回流中第一個元素 */ @Test public void testFindFirsth() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); Optional<String> first = list.stream().findFirst(); System.out.println("first = " + first.get()); } /** * findAny:返回流中第一個元素 */ @Test public void testFindAny() { List<String> list = new ArrayList<>(); list.add("張三三"); list.add("李四"); list.add("李四"); list.add("王五"); list.add("王五"); list.add("孫七"); list.add("趙八"); list.add("王二麻子"); Optional<String> any = list.stream().findAny(); System.out.println("any = " + any.get()); } /** * max:返回流中元素最大值 */ @Test public void testMax() { List<Integer> list = new ArrayList<>(); list.add(11); list.add(22); list.add(33); list.add(44); list.add(55); list.add(66); list.add(77); list.add(88); Integer integer = list.stream().max(Integer::compareTo).get(); System.out.println("integer = " + integer); } /** * min:返回流中元素最小值 */ @Test public void testMin() { List<Integer> list = new ArrayList<>(); list.add(11); list.add(22); list.add(33); list.add(44); list.add(55); list.add(66); list.add(77); list.add(88); Integer integer = list.stream().min(Integer::compareTo).get(); System.out.println("integer = " + integer); list.stream().limit(1).limit(2).distinct().skip(3).filter(f -> f.equals(55)).forEach(System.out::println); } }
總結(jié)
以上就是對于JDK1.8中Stream流式計算的一個簡單介紹,關(guān)于JDK1.8中的新特性,用法遠遠不止這些,這篇文章只作為一個簡單的入門使用,更多相關(guān)Java8 Stream流式操作內(nèi)容請搜索億速云以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持億速云!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。