Java8新特性Stream的常見用法

Stream簡介

Stream流是java 8 中新引入的特性,用來處理集合中的資料,它與 java。io 包裡的 InputStream 和 OutputStream 是完全不同的概念。

Stream不是資料結構,也不儲存資料,它是有關演算法和計算的,更像一個高階版本的迭代器Iterator。原始版本的 Iterator,只能顯式地一個一個遍歷元素並對其執行某些操作;高階版本的 Stream,只要給出需要對其包含的元素執行什麼操作,比如 “過濾掉長度大於 10 的字串”、“判斷是否包含某個字元”等,Stream 會隱式地在內部進行遍歷,做出相應的資料轉換。

Stream API 藉助於同樣新出現的 Lambda 表示式,極大的提高程式設計效率和程式可讀性。同時它提供序列和並行兩種模式進行匯聚操作,可以很方便地寫出高效能的併發程式。

Stream的使用

流操作的型別有三種:

(1)建立流

(2)修改流元素(中間操作,Intermediate Operations)

(3)消費流元素(終端操作,Terminal Operations)

建立流

流有兩種:

(1)stream() : 建立序列流。(2)parallelStream() : 建立並行流。

並行流的特點就是將一個大任務切分成多個小任務,無序一起執行,當然如果我們需要順序輸出的話可以使用forEachOrdered,速度會比序列流快一些。它透過預設的ForkJoinPool,可能提高你的多執行緒任務的速度。

(1) 透過Stream。of()將元素轉化成流

Stream。of建立流Stream stream = Stream。of(“你”, “我”, “她”);

(2)每個集合都可以透過呼叫 stream() 方法來產生一個流

//String [] strArray = new String[] {“a”, “b”, “c”};stream = Stream。of(strArray);stream = Arrays。stream(strArray);// List list = Arrays。asList(strArray);stream = list。stream();//Set w = new HashSet<>(Arrays。asList(strArray))stream = w。stream();

使用舉例

案例裡使用的類

class Person { private String name; // 姓名 private int salary; // 戰鬥力 private int age; // 年齡 private String sex; //性別 private String area; // 必殺技 // 構造方法 public Person(String name, int salary, int age,String sex,String area) { this。name = name; this。salary = salary; this。age = age; this。sex = sex; this。area = area; } public String getName() { return name; } public void setName(String name) { this。name = name; } public int getSalary() { return salary; } public void setSalary(int salary) { this。salary = salary; } public int getAge() { return age; } public void setAge(int age) { this。age = age; } public String getSex() { return sex; } public void setSex(String sex) { this。sex = sex; } public String getArea() { return area; } public void setArea(String area) { this。area = area; } @Override public String toString() { return “Person{” + “name=‘” + name + ’\‘’ + “, salary=” + salary + “, age=” + age + “, sex=‘” + sex + ’\‘’ + “, area=‘” + area + ’\‘’ + ‘}’; } }

(1) 遍歷/匹配(foreach/find/match)

Stream也是支援類似集合的遍歷和匹配元素的,只是Stream中的元素是以Optional型別存在的。Optional類是一個可以為null的容器物件,呼叫get()方法會返回該物件。

@Test public void streamTest1() { List personList = new ArrayList(); personList。add(new Person(“鳴人”, 8900, 18, “1”,“螺旋丸”)); personList。add(new Person(“佐助”, 8800, 18, “1”,“須佐能乎”)); personList。add(new Person(“小櫻”, 7800, 17, “2”,“治療術”)); personList。add(new Person(“自來也”, 8200, 30, “1”,“通靈術”)); personList。add(new Person(“大蛇丸”, 9500, 30, “1”,“八岐大蛇”)); personList。add(new Person(“綱手”, 7900, 29, “2”,“百豪之術”)); // 遍歷輸出符合條件的物件, 戰鬥力大於8000 personList。stream()。filter(person -> person。getSalary() > 8000)。forEach(System。out::println); // 匹配第一個 Optional findFirst = personList。stream()。filter(person -> person。getAge() > 18)。findFirst(); System。out。println(“匹配第一個值:” + findFirst。get()); // 匹配隨機一個(適用於並行流) Optional findAny = personList。parallelStream()。filter(person -> person。getAge() > 18)。findAny(); System。out。println(“匹配隨機一個值:” + findAny。get()); // 是否包含符合特定條件 年齡大於20 boolean anyMatch = personList。stream()。anyMatch(person -> person。getAge() > 20); System。out。println(“是否存在年齡大於20的:” + anyMatch); }

執行結果:

Java8新特性Stream的常見用法

(2)篩選(filter)

篩選,是按照一定的規則校驗流中的元素,將符合條件的元素提取到新的流中的操作。

@Test public void streamTest2() { List personList = new ArrayList(); personList。add(new Person(“鳴人”, 8900, 18, “1”,“螺旋丸”)); personList。add(new Person(“佐助”, 8800, 18, “1”,“須佐能乎”)); personList。add(new Person(“小櫻”, 7800, 17, “2”,“治療術”)); personList。add(new Person(“自來也”, 8200, 30, “1”,“通靈術”)); personList。add(new Person(“大蛇丸”, 9500, 30, “1”,“八岐大蛇”)); personList。add(new Person(“綱手”, 7900, 29, “2”,“百豪之術”)); //篩選出所有戰鬥力大於8000的 List list = personList。stream()。filter(person -> person。getSalary() > 8000)。collect(Collectors。toList()); System。out。println(“戰鬥力大於8000的值:” + list); }

執行結果:

Java8新特性Stream的常見用法

(3)聚合(max/min/count/sum)

max、min、count、sum這些字眼你一定不陌生,沒錯,在mysql中我們常用它們進行資料統計。Java stream中也引入了這些概念和用法,極大地方便了我們對集合、陣列的資料統計工作。

@Test public void streamTest3() { List personList = new ArrayList(); personList。add(new Person(“鳴人”, 8900, 18, “1”,“螺旋丸”)); personList。add(new Person(“佐助”, 8800, 18, “1”,“須佐能乎”)); personList。add(new Person(“小櫻”, 7800, 17, “2”,“治療術”)); personList。add(new Person(“自來也”, 8200, 30, “1”,“通靈術”)); personList。add(new Person(“大蛇丸”, 9500, 31, “1”,“八岐大蛇”)); personList。add(new Person(“綱手”, 7900, 29, “2”,“百豪之術”)); //獲取年齡最大的 Optional max = personList。stream()。max(Comparator。comparing(Person::getAge)); System。out。println(“年齡最大的是:” + max。get()); //獲取戰鬥力最小的 Optional min = personList。stream()。min(Comparator。comparing(Person::getSalary)); System。out。println(“戰鬥力最小的是:” + min。get()); //計算戰鬥力大於8000的有幾個人 long count = personList。stream()。filter(person -> person。getSalary() > 8000)。count(); System。out。println(“戰鬥力大於8000的人數是:” + count); //計算總年齡是多少 int sum = personList。stream()。mapToInt(person -> person。getAge())。sum(); System。out。println(“總年齡是是:” + sum); }

執行結果:

Java8新特性Stream的常見用法

(4)排序(sorted)

stream中有兩種排序:

sorted():自然排序,流中元素需實現Comparable介面

sorted(Comparator com):自定義排序,自定義Comparator排序器

@Test public void streamTest4() { List personList = new ArrayList(); personList。add(new Person(“鳴人”, 8900, 18, “1”,“螺旋丸”)); personList。add(new Person(“佐助”, 8800, 18, “1”,“須佐能乎”)); personList。add(new Person(“小櫻”, 7800, 17, “2”,“治療術”)); personList。add(new Person(“自來也”, 8200, 30, “1”,“通靈術”)); personList。add(new Person(“大蛇丸”, 9500, 31, “1”,“八岐大蛇”)); personList。add(new Person(“綱手”, 7900, 29, “2”,“百豪之術”)); //按戰鬥力升序排序(自然排序) List newList = personList。stream()。sorted(Comparator。comparing(Person::getSalary))。collect(Collectors。toList()); System。out。println(“按戰鬥力升序排序:” + newList); //按戰鬥力降序排序(自然排序) List newList2 = personList。stream()。sorted(Comparator。comparing(Person::getSalary)。reversed())。collect(Collectors。toList()); System。out。println(“按戰鬥力降序排序:” + newList2); // 先按年齡再按戰鬥力排序(自定義排序 降序) List newList3 = personList。stream()。sorted((p1, p2) -> { if (p1。getAge() == p2。getAge()) { return p2。getSalary() - p1。getSalary(); } else { return p2。getAge() - p1。getAge(); } })。collect(Collectors。toList()); System。out。println(“先按年齡再按戰鬥力:” + newList3); }

執行結果:

Java8新特性Stream的常見用法

(5) 對映(map/flatMap)

對映,可以將一個流的元素按照一定的對映規則對映到另一個流中。分為map和flatMap:

map:接收一個函式作為引數,該函式會被應用到每個元素上,並將其對映成一個新的元素。

flatMap:接收一個函式作為引數,將流中的每個值都換成另一個流,然後把所有流連線成一個流。

@Test public void streamTest5() { List personList = new ArrayList(); personList。add(new Person(“鳴人”, 8900, 18, “1”,“螺旋丸”)); personList。add(new Person(“佐助”, 8800, 18, “1”,“須佐能乎”)); personList。add(new Person(“小櫻”, 7800, 17, “2”,“治療術”)); personList。add(new Person(“自來也”, 8200, 30, “1”,“通靈術”)); personList。add(new Person(“大蛇丸”, 9500, 31, “1”,“八岐大蛇”)); personList。add(new Person(“綱手”, 7900, 29, “2”,“百豪之術”)); //將人物和必殺技組合, List strList = personList。stream()。map(person -> person。getName() + “——>” + person。getArea())。collect(Collectors。toList()); System。out。println(“人物和必殺技組合:” + strList); }

執行結果:

Java8新特性Stream的常見用法

(6)歸約(reduce)

歸約,也稱縮減,顧名思義,是把一個流縮減成一個值,能實現對集合求和、求乘積和求最值操作。

@Test public void streamTest6() { List personList = new ArrayList(); personList。add(new Person(“鳴人”, 8900, 18, “1”,“螺旋丸”)); personList。add(new Person(“佐助”, 8800, 18, “1”,“須佐能乎”)); personList。add(new Person(“小櫻”, 7800, 17, “2”,“治療術”)); personList。add(new Person(“自來也”, 8200, 30, “1”,“通靈術”)); personList。add(new Person(“大蛇丸”, 9500, 31, “1”,“八岐大蛇”)); personList。add(new Person(“綱手”, 7900, 29, “2”,“百豪之術”)); //求戰鬥力總和 方式1 Integer sum = personList。stream()。map(Person::getSalary)。reduce((x,y) -> x + y)。get(); System。out。println(“戰鬥力總和(方式1):” + sum); //求戰鬥力總和 方式2 Integer sum2 = personList。stream()。map(Person::getSalary)。reduce(Integer::sum)。get(); System。out。println(“戰鬥力總和(方式2):” + sum2); //求戰鬥力總和 方式3 Integer sum3 = personList。stream()。map(Person::getSalary)。reduce(0,Integer::sum); System。out。println(“戰鬥力總和(方式3):” + sum3); //求年齡的乘積 Integer product = personList。stream()。map(Person::getAge)。reduce((x,y) -> x * y)。get(); System。out。println(“年齡的乘積:” + product); //求戰鬥力最大的值 Integer max = personList。stream()。map(Person::getSalary)。reduce(1,Integer::max); System。out。println(“鬥力最大的值:” + max); }

執行結果:

Java8新特性Stream的常見用法

(7)收集(collect)

收集,可以說是內容最繁多、功能最豐富的部分了。從字面上去理解,就是把一個流收集起來,最終可以是收整合一個值也可以收整合一個新的集合。主要依賴java。util。stream。Collectors類內建的靜態方法。

(8)歸集(toList/toSet/toMap)

因為流不儲存資料,那麼在流中的資料完成處理後,需要將流中的資料重新歸集到新的集合裡。toList、toSet和toMap是比較常見的用法

@Test public void streamTest7() { List personList = new ArrayList(); personList。add(new Person(“鳴人”, 8900, 18, “1”, “螺旋丸”)); personList。add(new Person(“佐助”, 8800, 18, “1”, “須佐能乎”)); personList。add(new Person(“小櫻”, 7800, 17, “2”, “治療術”)); personList。add(new Person(“自來也”, 8200, 30, “1”, “通靈術”)); personList。add(new Person(“大蛇丸”, 9500, 31, “1”, “八岐大蛇”)); personList。add(new Person(“綱手”, 7900, 29, “2”, “百豪之術”)); //必殺技list集合 List list = personList。stream()。map(person -> person。getArea())。collect(Collectors。toList()); System。out。println(“必殺技集合toList:” + list); //大於18的年齡set集合 Set set = personList。stream()。filter(person -> person。getAge() > 18)。map(Person::getAge)。collect(Collectors。toSet()); System。out。println(“大於18的年齡集合toSet:” + set); //戰鬥力大於8000的map集合 (寫法1) Map<?, Person> map = personList。stream()。filter(p -> p。getSalary() > 8000) 。collect(Collectors。toMap(Person::getName, p -> p)); System。out。println(“戰鬥力大於8000的集合toMap:” + map); //戰鬥力大於8000的map集合 (寫法2) Map<?, Person> map2 = personList。stream()。filter(p -> p。getSalary() > 8000) 。collect(Collectors。toMap(Person::getName, Function。identity())); System。out。println(“戰鬥力大於8000的集合toMap:” + map2); }

執行結果:

Java8新特性Stream的常見用法

總結

好了,以上就是我總結的Stream的常見用法,感謝大家的閱讀,如果有什麼疑問或者建議,歡迎評論區留下你的獨到見解~