StreamAPI的說明
Java8中有兩大最為重要的改變。第一個是 Lambda 表達式;另外一個則是 Stream API。
Stream API ( java.util.stream) 把真正的函數式編程風格引入到Java中。這是目前為止對Java類庫最好的補充,因為Stream API可以極大提供Java程序員的生產力,讓程序員寫出高效率、干凈、簡潔的代碼。
Stream 是 Java8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常復雜的查找、過濾和映射數據等操作。 使用Stream API 對集合數據進行操作,就類似於使用 SQL 執行的數據庫查詢。也可以使用 Stream API 來並行執行操作。簡言之,Stream API 提供了一種高效且易於使用的處理數據的方式。
為什么要用StreamAPI
實際開發中,項目中多數數據源都來自於Mysql,Oracle等。但現在數據源可以更多了,有MongDB,Radis等,而這些NoSQL的數據就需要java層面去處理。
Stream到底是是什么
是數據渠道,用於操作數據源(集合、數組等)所生成的元素序列。“集合講的是數據,Stream講的是計算!”
注意:
Stream 自己不會存儲元素。
Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。
Stream 操作是延遲執行的。這意味着他們會等到需要結果的時候才執行。
Stream操作的三個步驟
1- 創建 Stream
一個數據源(如:集合、數組),獲取一個流
2- 中間操作
一個中間操作鏈,對數據源的數據進行處理
3- 終止操作(終端操作)
一旦執行終止操作,就執行中間操作鏈,並產生結果。之后,不會再被使用
如圖所示:
創建Stream
有三種方式:
1、通過集合(Java8中的Collection接口被擴展沒提供了兩個獲取流的方法 Stream() parallelStream())
2、通過數組(Java8 中的 Arrays 的靜態方法 stream() 可以獲取數組流 static
3、通過Stream的of()方法(可以調用Stream類靜態方法 of(), 通過顯示值創建一個流。它可以接收任意數量的參數 public static
首先有個Person類
package com.xnn.lambda;
/**
* 類(接口)描述:
* @author xnn
* 2018年10月21日下午3:05:37
*/
public class Person {
private String name;
private int age;
private double salary;
private Status status;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
/**
* @return the salary
*/
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
/**
* @param name
* @param age
* @param salary
* @param status
*/
public Person(String name, int age, double salary, Status status) {
super();
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
public Person() {
super();
}
/**
* @return the status
*/
public Status getStatus() {
return status;
}
/**
* @param status the status to set
*/
public void setStatus(Status status) {
this.status = status;
}
/**
* @param name
* @param age
* @param salary
*/
public Person(String name, int age, double salary) {
super();
this.name = name;
this.age = age;
this.salary = salary;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(salary);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((status == null) ? 0 : status.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(salary) != Double
.doubleToLongBits(other.salary))
return false;
if (status != other.status)
return false;
return true;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", salary=" + salary
+ ", status=" + status + "]";
}
public enum Status {
FREE,
BUSY,
VACATION;
}
}
package com.xnn.stream;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.Test;
import com.xnn.lambda.Person;
/**
* 類(接口)描述:Stream 操作的三個步驟
* 1.創建流
* 2.做一些中間操作
* 3.做終止操作
* @author xnn
* 2018年10月22日下午2:56:26
*/
public class TestStreamAPI {
//獲取流的第一種方式 (Java8中的Collection接口被擴展沒提供了兩個獲取流的方法 Stream() parallelStream())
List<Person> person = Arrays.asList(
new Person("李四", 59, 6666.66),
new Person( "張三", 18, 9999.99),
new Person( "王五", 28, 3333.33),
new Person( "趙六", 8, 7777.77),
new Person( "田七", 38, 5555.55)
);
@Test
public void test1() {
//獲取一個順序流
Stream<Person> stream = person.stream();
System.out.println(stream);
//獲取一個並行流
Stream<Person> parallelStream = person.parallelStream();
System.out.println(parallelStream);
//獲取流的第二種方式 ——由數組創建流
Integer arr[] = new Integer[] {1,4,5,6,78,7};
Stream<Integer> stream2 = Arrays.stream(arr);
Optional<Integer> first = stream2.findFirst();
System.out.println(first);
//獲取流的第三種方式——可以使用靜態方法 Stream.of(),即用值創建流
Stream<String> stream3 = Stream.of("y7yiu");
}
@Test
public void test2() {
//創建無限流
//迭代的方式創建無限流
Stream.iterate(0,(x)->x+2).limit(10)
.forEach(System.out::println);;
//生成的方式產生無限流
Stream.generate(()->Math.random()).limit(3).forEach(System.out::println);;
}
}
運行結果:
java.util.stream.ReferencePipeline$Head@5ef04b5
java.util.stream.ReferencePipeline$Head@5f4da5c3
Optional[1]
0
2
4
6
8
10
12
14
16
18
0.20849306218015928
0.526378190370348
0.6520277965773994
Stream的中間操作
多個中間操作可以連接起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理!而在終止操作時一次性全部處理,稱為“惰性求值”。
中間操作——篩選與切片
代碼示例
*
*/
package com.xnn.stream;
import java.net.StandardSocketOptions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import com.xnn.lambda.Person;
import com.xnn.lambda.Person.Status;
/**
* 類(接口)描述://中間操作
*
* @author xnn 2018年10月22日下午3:27:12
*/
public class TestStreamAPI2 {
List<Person> person = Arrays.asList(
new Person("李四", 59, 6666.66, Status.FREE),
new Person("張三", 18, 9999.99, Status.FREE),
new Person("王五", 28, 3333.33, Status.BUSY),
new Person("趙六", 8, 7777.77, Status.VACATION),
new Person("田七", 38, 5555.55, Status.BUSY),
new Person("田七", 38, 5555.55, Status.VACATION),
new Person("田七", 38, 5555.55, Status.VACATION)
);
/*
* 篩選與切片 filter——接收 Lambda , 從流中排除某些元素。 limit——截斷流,使其元素不超過給定數量。
* skip(n) ——跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。
* 與 limit(n) 互補
* distinct——篩選,通過流所生成元素的 hashCode() 和 equals() 去除重復元素
*/
@Test
public void test1() {
// 先獲取流
Stream<Person> stream = person.stream();
// 篩選 Stream<T> filter(Predicate<? super T> predicate);
// Predicate接口的test方法 傳遞進去一個T 返回一個Boolean
// filter——接收 Lambda , 從流中排除某些元素
// 這個forEach被稱為是內部迭代
stream.filter((u) -> {
System.out.println("中間操作");
//篩選出年齡大於20 的人員
return u.getAge() > 20;
}).forEach(System.out::println);
System.out.println("==============================");
/**
* 下面這一部分由於沒有終止操作,所以"中間操作"這四個字並沒有打印出來,只有當做終止操作時,所有的中間操作會一次性的全部執行,稱為“惰性求值”
*/
Stream<Person> stream4 = person.stream();
stream4.filter((u) -> {
System.out.println("中間操作");
return u.getAge() > 20;
});
System.out.println("==============================");
// 必須再創建一個新流 目測是新功能的時候,不能用上面的流,否則會報流已經打開或關閉的錯誤
Stream<Person> stream1 = person.stream();
// limit——截斷流,使其元素不超過給定數量
//篩選出年齡大於20歲的人元信息后,只取前兩個值
stream1.filter((u) -> u.getAge() > 20).limit(2)
.forEach(System.out::println);
System.out.println("==============================");
// skip(n) —— 跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit(n) 互補
Stream<Person> stream2 = person.stream();
//篩選出年齡大於20歲的人元信息后,跳過第一個人,取后面的值
stream2.filter((u) -> u.getAge() > 20).skip(1)
.forEach(System.out::println);
System.out.println("==============================");
// distinct——篩選,通過流所生成元素的 hashCode() 和 equals()這樣去除重復元素(意即需要重寫實體類的hashcode 和equals方法)
Stream<Person> stream3 = person.stream();
stream3.filter((u) -> u.getAge() > 20).distinct()
.forEach(System.out::println);
}
}
運行結果:
中間操作——映射
代碼示例
package com.xnn.stream;
import java.net.StandardSocketOptions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import com.xnn.lambda.Person;
import com.xnn.lambda.Person.Status;
/**
* 類(接口)描述://中間操作
*
* @author xnn 2018年10月22日下午3:27:12
*/
public class TestStreamAPI2 {
List<Person> person = Arrays.asList(
new Person("李四", 59, 6666.66, Status.FREE),
new Person("張三", 18, 9999.99, Status.FREE),
new Person("王五", 28, 3333.33, Status.BUSY),
new Person("趙六", 8, 7777.77, Status.VACATION),
new Person("田七", 38, 5555.55, Status.BUSY),
new Person("田七", 38, 5555.55, Status.VACATION),
new Person("田七", 38, 5555.55, Status.VACATION)
);
/**
* 映射: 1、map(Function f) 接收一個函數作為參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。
* 2、mapToDouble(ToDoubleFunction f)) 接收一個函數作為參數,該函數會被應用到每個素上,產生一個新的
* DoubleStream 3、mapToInt(ToIntFunction f)接收一個函數作為參數,該函數會被應用到每個元素上,產生一個新的
* IntStream。 4、mapToLong(ToLongFunction f) 接收一個函數作為參數,該函數會被應用到每個元素上,產生一個新的
* LongStream 5、flatMap(Function f) 接收一個函數作為參數,將流中的每個值都換成另一個流,然后把所有流連接成一個流
*
* @author:xnn 2018年10月22日下午3:55:54
*/
@Test
public void test2() {
Stream<Person> stream = person.stream();
// 1、map(Function f) 接收一個函數作為參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。
// 把姓名的集合取出來
// stream.map((x)->x.getName()).forEach(System.out::println);
//方法引用的方式寫的
stream.map(Person::getName).forEach(System.out::println);
System.out.println("================");
// 2、mapToDouble(ToDoubleFunction f)) 接收一個函數作為參數,該函數會被應用到每個素上,產生一個DoubleStream
Stream<Person> stream1 = person.stream();
// stream1.mapToDouble((x)->x.getSalary())
// .forEach(System.out::println);
// 另一種寫法 即:接受了Person類的getSalary()方法為參數,把薪資全都取出胡來了
stream1.mapToDouble(Person::getSalary).forEach(System.out::println);
System.out.println("================");
// 3、mapToInt(ToIntFunction f)接收一個函數作為參數,該函數會被應用到每個元素上,產生一個新的 IntStream。
Stream<Person> stream2 = person.stream();
stream2.mapToInt(Person::getAge).forEach(System.out::println);
System.out.println("================");
Stream<String> stream3 = Stream.of("aaa", "bbb", "ccc", "ddd");
Stream<Stream<Character>> map =
/*TestStreamAPI2::filterCharacter就代表把每一個字符串("aaa","bbb"...)都進行filterCharacter()處理,
這時候每個字母,都變成了一個流,而map()方法返回的也是一個流,所以返回值就成了Stream<Stream<Character>>*/
stream3.map(TestStreamAPI2::filterCharacter);
//用map的話還得多重遍歷(sm 代表一個Stream<Character>,所以再對sm進行了遍歷)
map.forEach((sm)->sm.forEach(System.out::println));
System.out.println("++++++++++++++++++++++++++");
// flatMap(Function f) 接收一個函數作為參數,將流中的每個值都換成另一個流,
//然后把所有流連接成一個流(是個關鍵)
Stream<String> stream4 = Stream.of("aaa", "bbb", "ccc", "ddd");
Stream<Character> flatMap = stream4
.flatMap(TestStreamAPI2::filterCharacter);
flatMap.forEach(System.out::println);
System.out.println("==============");
/**
* map 和flatmap類似於list集合的add()方法和addAll()方法
*/
List<Object> list =new ArrayList<>();
List<Object> list2 =new ArrayList<>();
list.add("aaa");
list.add("bbb");
list2.add("1");
//add是把集合加進去了
list2.add(list);
System.out.println(list2);
System.out.println("+++++++++++++++++++++++++");
List<Object> list3 =new ArrayList<>();
List<Object> list4 =new ArrayList<>();
list3.add("aaa");
list3.add("bbb");
list4.add("1");
//addAll是把集合中的每一個元素加進去了
list4.addAll(list3);
System.out.println(list4);
}
// 把字符串轉化為字符數組流
public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
}
運行結果
李四
張三
王五
趙六
田七
田七
田七
================
6666.66
9999.99
3333.33
7777.77
5555.55
5555.55
5555.55
================
59
18
28
8
38
38
38
================
a
a
a
b
b
b
c
c
c
d
d
d
++++++++++++++++++++++++++
a
a
a
b
b
b
c
c
c
d
d
d
==============
用add的結果:[1, [aaa, bbb]]
+++++++++++++++++++++++++
用addAll的結果:[1, aaa, bbb]
中間操作——排序
代碼示例
package com.xnn.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import com.xnn.lambda.Person;
import com.xnn.lambda.Person.Status;
/**
* 類(接口)描述://中間操作
*
* @author xnn 2018年10月22日下午3:27:12
*/
public class TestStreamAPI2 {
List<Person> person = Arrays.asList(
new Person("李四", 59, 6666.66, Status.FREE),
new Person("張三", 18, 9999.99, Status.FREE),
new Person("王五", 28, 3333.33, Status.BUSY),
new Person("趙六", 8, 7777.77, Status.VACATION),
new Person("田七", 38, 5555.55, Status.BUSY),
new Person("田七", 38, 5555.55, Status.VACATION),
new Person("田七", 38, 5555.55, Status.VACATION)
);
/**
* sorted() 產生一個新流,其中按自然順序 sorted(Comparator comp) 產生一個新流,其中按比較器順序
*/
@Test
public void test3() {
// sorted() 產生一個新流,其中按自然順序
List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ee");
Stream<String> stream = list.stream();
stream.sorted().forEach(System.out::println);
System.out.println("-------------------------");
// sorted(Comparator comp) 產生一個新流,其中按比較器順序
person.stream().sorted((e1, e2) -> {
/**
* 年齡相同按姓名排序,否則按年齡排序
*/
if (e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
} else {
return Integer.compare(e1.getAge(), e2.getAge());
}
}).forEach(System.out::println);;
}
}
運行結果
aa
bb
cc
dd
ee
-------------------------
Person [name=趙六, age=8, salary=7777.77, status=VACATION]
Person [name=張三, age=18, salary=9999.99, status=FREE]
Person [name=王五, age=28, salary=3333.33, status=BUSY]
Person [name=田七, age=38, salary=5555.55, status=BUSY]
Person [name=田七, age=38, salary=5555.55, status=VACATION]
Person [name=田七, age=38, salary=5555.55, status=VACATION]
Person [name=李四, age=59, salary=6666.66, status=FREE]
Stream 的終止操作
終端操作會從流的流水線生成結果。其結果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
流進行了終止操作后,不能再次使用。
終止操作——匹配與查找
代碼示例
package com.xnn.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import com.xnn.lambda.Person;
import com.xnn.lambda.Person.Status;
/**
* 類(接口)描述://中間操作
*
* @author xnn 2018年10月22日下午3:27:12
*/
public class TestStreamAPI2 {
List<Person> person = Arrays.asList(
new Person("李四", 59, 6666.66, Status.FREE),
new Person("張三", 18, 9999.99, Status.FREE),
new Person("王五", 28, 3333.33, Status.BUSY),
new Person("趙六", 8, 7777.77, Status.VACATION),
new Person("田七", 38, 5555.55, Status.BUSY),
new Person("田七", 38, 5555.55, Status.VACATION),
new Person("田七", 38, 5555.55, Status.VACATION)
);
/**
* stream的終止操作(查找與匹配)
* 1、allMatch(Predicate p) 檢查是否匹配所有元素
* 2、anyMatch(Predicate p) 檢查是否至少匹配一個元素
* 3、noneMatch(Predicate p)檢查是否沒有匹配所有元素
* 4、findFirst() 返回第一個元素
* 5、findAny() 返回當前流中的任意元素
* @author:xnn 2018年10月23日下午2:48:07
*/
@Test
public void test4() {
// allMatch(Predicate p) 檢查是否匹配所有元素,即所有元素的status是BUSY才返回true
boolean b = person.stream()
.allMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(b);
System.out.println("===================");
// anyMatch(Predicate p) 檢查是否至少匹配一個元素,只要有一個元素的status是BUSY就返回true
boolean c = person.stream()
.anyMatch((w) -> w.getStatus().equals(Status.BUSY));
System.out.println(c);
System.out.println("===================");
// noneMatch(Predicate p) 檢查是否沒有匹配所有元素,即 所有的元素的status都不是BUSY才返回true
boolean d = person.stream()
.noneMatch((q) -> q.getStatus().equals(Status.BUSY));
System.out.println(d);
System.out.println("===================");
// findFirst() 返回第一個元素,返回符合條件的第一個元素
Optional<Person> findFirst = person.stream().sorted(
(e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(findFirst.get());
System.out.println("========================");
// findAny() 返回當前流中的任意元素()
Optional<Person> any = person.parallelStream()
.filter((e) -> e.getStatus().equals(Status.BUSY)).findAny();
System.out.println(any);
}
}
運行結果
false
===================
true
===================
false
===================
Person [name=王五, age=28, salary=3333.33, status=BUSY]
========================
Optional[Person [name=田七, age=38, salary=5555.55, status=BUSY]]
終止操作——匹配與查找二
代碼示例:
package com.xnn.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import com.xnn.lambda.Person;
import com.xnn.lambda.Person.Status;
/**
* 類(接口)描述://中間操作
*
* @author xnn 2018年10月22日下午3:27:12
*/
public class TestStreamAPI2 {
List<Person> person = Arrays.asList(
new Person("李四", 59, 6666.66, Status.FREE),
new Person("張三", 18, 9999.99, Status.FREE),
new Person("王五", 28, 3333.33, Status.BUSY),
new Person("趙六", 8, 7777.77, Status.VACATION),
new Person("田七", 38, 5555.55, Status.BUSY),
new Person("田七", 38, 5555.55, Status.VACATION),
new Person("田七", 38, 5555.55, Status.VACATION)
);
/**
* 1、count() 返回流中元素總數
* 2、max(Comparator c) 返回流中最大值
* 3、min(Comparator c)返回流中最小值
* 4、forEach(Consumer c) 內部迭代(使用 Collection接口需要用戶去做迭代,稱為外部迭代。相反,Stream API 使用內部迭代——它幫你把迭代做
*/
@Test
public void test5() {
// count() 返回流中元素總數
long count = person.stream().count();
System.out.println(count);
System.out.println("=======華麗的分割線========");
// max(Comparator c) 返回流中最大值
Optional<Person> max = person.stream().max(
(e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println("最高工資員工為" + max);
System.out.println("=======華麗的分割線========");
// min(Comparator c) 返回流中最小值
Optional<Person> min = person.stream().min(
(e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println("最低工資員工為" + min);
}
}
運行結果
7
=======華麗的分割線========
最高工資員工為Optional[Person [name=張三, age=18, salary=9999.99, status=FREE]]
=======華麗的分割線========
最低工資員工為Optional[Person [name=王五, age=28, salary=3333.33, status=BUSY]]
終止操作——歸約
map 和 reduce 的連接通常稱為 map-reduce 模式,因 Google 用它來進行網絡搜索而出名。
代碼示例:
package com.xnn.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import com.xnn.lambda.Person;
import com.xnn.lambda.Person.Status;
/**
* 類(接口)描述://中間操作
*
* @author xnn 2018年10月22日下午3:27:12
*/
public class TestStreamAPI2 {
List<Person> person = Arrays.asList(
new Person("李四", 59, 6666.66, Status.FREE),
new Person("張三", 18, 9999.99, Status.FREE),
new Person("王五", 28, 3333.33, Status.BUSY),
new Person("趙六", 8, 7777.77, Status.VACATION),
new Person("田七", 38, 5555.55, Status.BUSY),
new Person("田七", 38, 5555.55, Status.VACATION),
new Person("田七", 38, 5555.55, Status.VACATION)
);
/**
* 歸約
* 1、reduce(T iden, BinaryOperator b) 可以將流中元素反復結合起來,得到一個值,返回 T
* 2、reduce(BinaryOperator b) 可以將流中元素反復結合起來,得到一個值。返回 Optional<T>
*/
@Test
public void test6() {
// reduce(T iden, BinaryOperator b) 可以將流中元素反復結合起來,得到一個值,返回 T
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
/**
* 先把0作為了x,y是流中的第一個元素 相加得1,然后1作為x,流中的第二個元素作為y,就這樣,依次加下去。
*/
Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(reduce);
System.out.println("=======華麗的分割線========");
// reduce(BinaryOperator b) 可以將流中元素反復結合起來,得到一個值。返回 Optional<T>
/**
* 可以看出兩個reduce方法返回的並不一樣,因為第一個reduce方法有初始值,最后所得的值肯定不會為空,而第二種情況則有可能會為空,所以返回值為跑optional
*/
Optional<Double> reduce2 = person.stream().map(Person::getSalary)
.reduce(Double::sum);
System.out.println(reduce2);
System.out.println("=======華麗的分割線========");
}
}
運行結果:
55
=======華麗的分割線========
Optional[44444.40000000001]
=======華麗的分割線========
終止操作——收集
Collector 接口中方法的實現決定了如何對流執行收集的操作(如收集到 List、Set、Map)。
另外, Collectors 實用類提供了很多靜態方法,可以方便地創建常見收集器實例,具體方法與實例如下表:
代碼示例
package com.xnn.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import com.xnn.lambda.Person;
import com.xnn.lambda.Person.Status;
/**
* 類(接口)描述://中間操作
*
* @author xnn 2018年10月22日下午3:27:12
*/
public class TestStreamAPI2 {
List<Person> person = Arrays.asList(
new Person("李四", 59, 6666.66, Status.FREE),
new Person("張三", 18, 9999.99, Status.FREE),
new Person("王五", 28, 3333.33, Status.BUSY),
new Person("趙六", 8, 7777.77, Status.VACATION),
new Person("田七", 38, 5555.55, Status.BUSY),
new Person("田七", 38, 5555.55, Status.VACATION),
new Person("田七", 38, 5555.55, Status.VACATION)
);
/**
* 收集: collect(Collector c) 將流轉換為其他形式。接收一個 Collector接口的實現,用於給Stream中元素做匯總的方法
*/
@Test
public void test7() {
//把人員的名字放到一個list中去
List<String> collect = person.stream().map(Person::getName)
.collect(Collectors.toList());
System.out.println(collect);
System.out.println("=======華麗的分割線=======");
//把人員的名字放到一個hashset中去(會自動去重)
HashSet<String> collect2 = person.stream().map(Person::getName)
.collect(Collectors.toCollection(HashSet::new));
System.out.println(collect2);
System.out.println("=======華麗的分割線=======");
//計數
Long long1 = person.stream().collect(Collectors.counting());
System.out.println(long1);
System.out.println("=======華麗的分割線=======");
// 按狀態分組
Map<Status, List<Person>> collect3 = person.stream()
.collect(Collectors.groupingBy((e) -> e.getStatus()));
System.out.println(collect3);
System.out.println("=======華麗的分割線=======");
// 多重分組(先按狀態分組,再按薪資是否大於5000分組)
Map<Status, Map<Boolean, List<Person>>> collect4 = person.stream()
.collect(Collectors.groupingBy((e) -> e.getStatus(),
Collectors.groupingBy((e) -> e.getSalary() > 5000)));
System.out.println(collect4);
System.out.println("=======華麗的分割線=======");
//取所有人員薪資的平均值
Double double1 = person.stream()
.collect(Collectors.averagingDouble((e) -> e.getSalary()));
System.out.println("所有人員薪資的平均值:"+double1);
System.out.println("=======華麗的分割線=======");
//把所有人的姓名拼接成一個字符串
String collect5 = person.stream().map(Person::getName)
.collect(Collectors.joining());
System.out.println(collect5);
System.out.println("=======華麗的分割線=======");
//找出所有人中薪資最少的一個員工的信息。
Optional<Person> optional = person.stream().collect(Collectors.minBy(
(e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(optional);
System.out.println("=======華麗的分割線=======");
}
}
運行結果
[李四, 張三, 王五, 趙六, 田七, 田七, 田七]
=======華麗的分割線=======
[李四, 張三, 王五, 趙六, 田七]
=======華麗的分割線=======
7
=======華麗的分割線=======
{BUSY=[Person [name=王五, age=28, salary=3333.33, status=BUSY], Person [name=田七, age=38, salary=5555.55, status=BUSY]], FREE=[Person [name=李四, age=59, salary=6666.66, status=FREE], Person [name=張三, age=18, salary=9999.99, status=FREE]], VACATION=[Person [name=趙六, age=8, salary=7777.77, status=VACATION], Person [name=田七, age=38, salary=5555.55, status=VACATION], Person [name=田七, age=38, salary=5555.55, status=VACATION]]}
=======華麗的分割線=======
{BUSY={false=[Person [name=王五, age=28, salary=3333.33, status=BUSY]], true=[Person [name=田七, age=38, salary=5555.55, status=BUSY]]}, FREE={true=[Person [name=李四, age=59, salary=6666.66, status=FREE], Person [name=張三, age=18, salary=9999.99, status=FREE]]}, VACATION={true=[Person [name=趙六, age=8, salary=7777.77, status=VACATION], Person [name=田七, age=38, salary=5555.55, status=VACATION], Person [name=田七, age=38, salary=5555.55, status=VACATION]]}}
=======華麗的分割線=======
所有人員薪資的平均值:6349.2
=======華麗的分割線=======
李四張三王五趙六田七田七田七
=======華麗的分割線=======
Optional[Person [name=王五, age=28, salary=3333.33, status=BUSY]]
=======華麗的分割線=======