簡介
Java8中有兩大最爲重要的改變。第一個是Lambda
表達式;另外一個則是Stream API(java.util.stream.*)
。
Stream
是Java8
中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常複雜的查找、過濾和映射數據等操作。使用Stream API
對集合數據進行操作,就類似於使用SQL 執行的數據庫查詢。也可以使用Stream API
來並行執行操作。簡而言之,Stream API
提供了一種高效且易於使用的處理數據的方式。
Stream
(流)是數據渠道,用於操作數據源(集合、數組等)所生成的元素序列。“集合講的是數據,流講的是計算!”
注意:
1.Stream
自己不會存儲元素。
2. Stream
不會改變源對象。相反,他們會返回一個持有結果的新Stream。
3. Stream
操作是延遲執行的。這意味着他們會等到需要結果的時候才執行
Stream操作步驟
- 創建Stream:一個數據源(如:集合、數組),獲取一個流
- 中間操作:一箇中間操作鏈,對數據源的數據進行處理
- 終止操作(終端操作):一個終止操作,執行中間操作鏈,併產生結果
流程如下圖所示:
創建Stream
方式一:Java8 中的Collection 接口被擴展,提供了兩個獲取流的方法:
default Stream<E> stream()
: 返回一個順序流default Stream<E> parallelStream()
: 返回一個並行流
// 1、 通過Collection集合提供的stream()或parallelStream()
List<String> list = new ArrayList<>();
// stream()
Stream<String> stream1 = list.stream();
// parallelStream()
Stream<String> parallelStream = list.parallelStream();
方式二:通過Arrays
中的靜態方法stream()
獲取數組流
// 2、通過Arrays中的靜態方法stream()獲取數組流
String[] strArray = {"1","2"};
Stream<String> stream2 = Arrays.stream(strArray);
方式三:通過stream類中的靜態方法of(),它可以接收任意數量的參數
// 通過stream類中的靜態方法of()
Stream<String> stream3 = Stream.of("1", "2");
方式四:創建無限流,可以使用靜態方法Stream.iterate()
和Stream.generate()
, 創建無限流
// 4、創建無限流
// 使用迭代
Stream<Integer> iterateStream = Stream.iterate(0, (e) -> e + 2);
iterateStream.limit(10).forEach(System.out::println);
// 使用生成
Stream<Double> generateStream = Stream.generate(() -> Math.random());
generateStream.limit(10).forEach(System.out::println);
Stream的中間操作
多箇中間操作可以連接起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理!而在終止操作時一次性全部處理,稱爲“惰性求值”
篩選與切片:
/**
* 切片與篩選
*
* filter(Predicatep):接收Lambda ,從流中排除某些元素。
* limit(long maxSize):截斷流,使其元素不超過給定數量。
* skip(long n):跳過元素,返回一個扔掉了前n 個元素的流。若流中
* distinct():篩選,通過流所生成元素的hashCode() 和equals() 去除重複元素
*/
@Test
public void test2(){
// 中間操作:不會執行任何操作
Stream<User> userStream = userList.stream().filter((e) -> {
System.out.println("stream 中間操作");
return e.getAge() > 20;
});
// 終止操作:一次性執行完全部內容,稱爲"惰性求值"
userStream.forEach(System.out::println);
}
// limit(long maxSize):截斷流,使其元素不超過給定數量
@Test
public void test3(){
userList.stream().limit(2).forEach(System.out::println);
}
// skip(long n):跳過元素,返回一個扔掉了前n 個元素的流。若流中
@Test
public void test4(){
userList.stream().skip(2).forEach(System.out::println);
}
// distinct():篩選,通過流所生成元素的hashCode() 和equals() 去除重複元素
@Test
public void test5(){
userList.stream().distinct().forEach(System.out::println);
}
映射:
/**
* 映射
*
*
* map(Functionf):接收一個函數作爲參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。
* flatMap(Function f):接收一個函數作爲參數,將流中的每個值都換成另一個流,然後把所有流連接成一個流
*/
// map(Functionf):接收一個函數作爲參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。
@Test
public void test6(){
userList.stream().map(User::getName).forEach(System.out::println);
}
// flatMap(Function f):接收一個函數作爲參數,將流中的每個值都換成另一個流,然後把所有流連接成一個流
@Test
public void test7() {
List<String> list = Arrays.asList("a a", "c c", "d d", "b b");
Stream<String> stringStream = list.stream().flatMap(e -> Arrays.stream(e.split(" ")));
stringStream.forEach(System.out::println);
}
排序:
/**
* 排序
*
* sorted():產生一個新流,其中按自然順序排序
* sorted(Comparatorcomp):產生一個新流,其中按比較器順序排序
*/
// sorted():產生一個新流,其中按自然順序排序
@Test
public void test8(){
List<String> list = Arrays.asList("a a", "c c", "d d", "b b");
list.stream().sorted().forEach(System.out::println);
}
// sorted(Comparatorcomp):產生一個新流,其中按比較器順序排序
@Test
public void test9(){
userList.stream().sorted((e1,e2) -> {
if(e1.getAge() > e2.getAge()){
return 1;
}
return 0;
}).forEach(System.out::println);
}
Stream的終止操作
查找與匹配:
/**
* 查找與匹配
*
* allMatch(Predicate p):檢查是否匹配所有元素
* anyMatch(Predicate p): 檢查是否至少匹配一個元素
* noneMatch(Predicatep):檢查是否沒有匹配所有元素
* findFirst():返回第一個元素
* findAny():返回當前流中的任意元素
* count():返回流中元素總數
* max(Comparatorc):返回流中最大值
* min(Comparatorc):返回流中最小值
* forEach(Consumerc):內部迭代(使用Collection 接口需要用戶去做迭代,稱爲外部迭代。相反,Stream API 使用內部迭代——它幫你把迭代做了)
*/
// allMatch(Predicate p):檢查是否匹配所有元素
@Test
public void test10() {
boolean b = userList.stream().allMatch((e) -> "男".equals(e.getGender()));
System.out.println("allMatch:" + b);
}
// anyMatch(Predicate p): 檢查是否至少匹配一個元素
@Test
public void test11(){
boolean b = userList.stream().anyMatch((e) -> "男".equals(e.getGender()));
System.out.println("anyMatch:" + b);
}
// noneMatch(Predicatep):檢查是否沒有匹配所有元素
@Test
public void test12(){
boolean b = userList.stream().noneMatch((e) -> "男".equals(e.getGender()));
System.out.println("noneMatch:" + b);
}
// findFirst():返回第一個元素
@Test
public void test13(){
Optional<User> first = userList.stream().findFirst();
System.out.println(first.get());
}
// findAny():返回當前流中的任意元素
@Test
public void test14(){
Optional<User> any = userList.stream().findAny();
System.out.println(any.get());
}
// count():返回流中元素總數
@Test
public void test15(){
long count = userList.stream().count();
System.out.println(count);
}
// max(Comparatorc):返回流中最大值
@Test
public void test16(){
Optional<User> max = userList.stream().max((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
System.out.println(max.get());
}
// min(Comparatorc):返回流中最小值
@Test
public void test17(){
Optional<User> max = userList.stream().min((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
System.out.println(max.get());
}
// forEach(Consumerc):內部迭代(使用Collection 接口需要用戶去做迭代,稱爲外部迭代。相反,Stream API 使用內部迭代——它幫你把迭代做了)
@Test
public void test18(){
userList.stream().forEach(System.out::println);
}
規約:
/**
* 規約
*
* reduce(T iden, BinaryOperator b):可以將流中元素反覆結合起來,得到一個值。返回T
* reduce(BinaryOperator b):可以將流中元素反覆結合起來,得到一個值。返回Optional<T>
*/
// reduce(T iden, BinaryOperator b):可以將流中元素反覆結合起來,得到一個值。返回T
@Test
public void test19() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(reduce);
}
// reduce(BinaryOperator b):可以將流中元素反覆結合起來,得到一個值。返回Optional<T>
@Test
public void test20(){
Optional<Integer> reduce = userList.stream().map(User::getAge).reduce(Integer::sum);
System.out.println(reduce.get());
}
收集:
/**
* 收集
*
* collect(Collector c):將流轉換爲其他形式。接收一個Collector接口的實現,用於給Stream中元素做彙總的方法
*
*/
@Test
public void test21() {
// toList
List<User> list = userList.stream().collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("-----------------------");
// toSet
Set<User> userSet = userList.stream().collect(Collectors.toSet());
userSet.forEach(System.out::println);
System.out.println("-----------------------");
// 計算流中元素的個數
Long count = userList.stream().collect(Collectors.counting());
System.out.println(count);
System.out.println("-----------------------");
// 平均值
Double avg = userList.stream().collect(Collectors.averagingDouble(User::getAge));
System.out.println(avg);
System.out.println("-----------------------");
// 總和
Double sum = userList.stream().collect(Collectors.summingDouble(User::getAge));
System.out.println(sum);
System.out.println("-----------------------");
// 最大值
Optional<User> max = userList.stream().collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
System.out.println(max.get());
System.out.println("-----------------------");
// 最小值
Optional<Integer> min = userList.stream().map(User::getAge).collect(Collectors.minBy(Integer::compare));
System.out.println(min);
System.out.println("-----------------------");
// 分組
Map<String, List<User>> group = userList.stream().collect(Collectors.groupingBy(User::getGender));
System.out.println(group);
System.out.println("-----------------------");
// 多級分組
Map<String, Map<Integer, List<User>>> multilevelGroup = userList.stream().collect(Collectors.groupingBy(User::getGender, Collectors.groupingBy(User::getAge)));
System.out.println(multilevelGroup);
System.out.println("-----------------------");
// 根據true或false進行分區
Map<Boolean, List<User>> area = userList.stream().collect(Collectors.partitioningBy((e) -> e.getGender().equals("男")));
System.out.println(area);
System.out.println("-----------------------");
// 求統計值
DoubleSummaryStatistics summaryStatistics = userList.stream().collect(Collectors.summarizingDouble(User::getAge));
System.out.println(summaryStatistics.getMax());
System.out.println(summaryStatistics.getMin());
System.out.println(summaryStatistics.getCount());
System.out.println(summaryStatistics.getAverage());
System.out.println("-----------------------");
// 連接字符串
String joining = userList.stream().map(User::getName).collect(Collectors.joining());
System.out.println(joining);
System.out.println("-----------------------");
// 連接字符串,按符號分隔
String joiningSp = userList.stream().map(User::getName).collect(Collectors.joining(","));
System.out.println(joiningSp);
// 從一個作爲累加器的初始值開始,利用BinaryOperator與流中元素逐個結合,從而歸約成單個值
Integer reducing = userList.stream().collect(Collectors.reducing(0, User::getAge, Integer::sum));
System.out.println(reducing);
// 包裹另一個收集器,對其結果轉換函數
Integer collectingAndThen = userList.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
System.out.println(collectingAndThen);
}