強大的Stream API
所在包爲: java.util.stream.*
Stream 是 java 8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常複雜的 查找、過濾和映射數據 等操作。使用 Stream api 的操作,就類似使用SQL 執行的數據庫查詢,。也可以使用 Stream API 來並行執行操作。
簡而言之,Stream API 提供了一種高效且易於使用的處理數據的方式。
1. 流(Stream) 到底是什麼?
流是數據渠道,用於操作數據源(集合、數組等)所生成的元素序列。、
”集合講的是數據,流講的是計算“
note: ① Stream 不會存儲元素
② Stream 不會改變源對象。相反,他們會返回一個持有結果的新的 Stream。
③ Stream 操作時延遲執行的。這意味着他們會等到需要結果的時候才執行。
2. Stream 操作三個步驟
- 創建 Stream
- 中間操作
- 終止操作(終端操作)
2.1 創建 Stream 的方式
// 1. 可以通過 Collection 系列集合提供的 stream() 或 parallelStream()
// stream() 獲取串行流;parallelStream() 獲取並行流;
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
// 2. 通過 Arrays 中的靜態方法 stream() 獲取數據流
Employee [] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
// 3. 通過 Stream 類中的靜態方法 of()
Stream<String> stream3 = Stream.of("a", "b", "c");
// 4. 創建無限流
// 迭代
// 函數式接口
// Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//
// @FunctionalInterface
// public interface UnaryOperator<T> extends Function<T, T> {
//
// static <T> UnaryOperator<T> identity() {
// return t -> t;
// }
// }
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x+2);
stream4.limit(10).forEach(System.out::println); // 中間操作+終止操作
// 生成
Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);
2.2 中間操作
-
/* 篩選和切片 filter ——接受 Lambda,從流中排除某些元素 limit —— 截斷流,使其元素不超過給定數量 skip(n) —— 跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit() 互補; 注意該方法所執行的位置, 會在其之前的其他篩選方法之後的結果上進行跳過元素 distinct —— 篩選,通過流所生成元素的 hashCode() 和 equals() 去重複元素 (故使用該方法篩選, 需要先重寫hashCode, equals ) */ Stream<String> stream = list.stream() .filter((e) -> { return e.getId() > 1; }) .skip(2) .limit(10) .distinct(); /* 映射 map —— 接受 lambda 表達式,將元素轉換成其他i形式或提取信息。接受一個函數作爲參數,該參數會被應用到每一個元素上,並將其映射成一個新的元素。 flatMap —— 接受一個函數作爲參數,將流中的每個值都換成另外一個流,然後把所有流連接成一個流 */ public class TestStream02 { @Test public void test(){ List<String> list = Arrays.asList("a", "b", "CC", "dd"); Stream<Stream<Character>> streamStream = list.stream() .map(TestStream02::filterCharacter); streamStream.forEach((x) -> { x.forEach(System.out::println); }); // 終止操作,打印輸出 System.out.println("======================================="); System.out.println("以上代碼效果與以下代碼相同"); System.out.println("======================================="); list.stream() .flatMap(TestStream02::filterCharacter) .forEach(System.out::println); } public static Stream<Character> filterCharacter(String str){ // 省略具體實現 } } /* 排序 sorted() —— 自然排序 (Comparable) sorted(Comparator com) —— 定製排序(Comparator), 自己實現 Comparator 函數式接口 */ List<String> list = Arrays.asList("a", "b", "CC", "dd"); list.stream().sorted().forEach(System.out::println); System.out.println("===================================="); employees.stream().sorted((e1, e2) -> { if(e1.getId() == e2.getId()) { return e1.getName().compareTo(e2.getName()); } else { return e1.getId().compareTo(e2.getId()); } }).forEach(System.out::println);
注:
中間操作 不會執行任何操作;直到發生 終止操作 才一次性執行全部內容,即"惰性求值"
2.3 終止操作(終端操作)
/*
1. 查找與匹配
allMatch —— 檢查是否匹配所有元素
anyMatch —— 檢查是否至少匹配一個元素
noneMatch —— 檢查是否沒有匹配所有元素
findFirst —— 返回第一個元素
findAny —— 返回當前流中的任意元素
count —— 返回流中元素的總個數
max —— 返回流中最大值
min —— 返回流中最小值
*/
// allMatch、anyMatch、noneMatch 實現 Predicate 函數式接口做匹配檢查
boolean b1 = employees.stream()
.allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
List<String> list = Arrays.asList("a", "b", "CC", "dd");
list.stream().findFirst();
list.stream().findAny();
list.stream().count();
Optional<String> op = list.stream().max(String::compareTo);
Optional<String> op = list.stream().min(String::compareTo);
/*
2. 規約
reduce(T identity, BinaryOperator) / reduce(BinaryOperator) —— 可以將流中元素反覆結合起來,得到一個值
*/
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// reduce(T identity, BinaryOperator)
// 0 代入 x, list的流一個一個元素代入y, 將計算結果重新代入 x, 將下一個元素代入 y
Integer sum = list.stream().reduce(0, (x, y) -> x+y);
System.out.println("==================================");
Optional<Integer> op = employees.stream().map(Employee::getId).reduce(Integer::sum);
System.out.println("op:" + op.get());
/*
3. 收集
collect —— 將流轉換爲其他形式。接受一個Collector 接口的實現,用於給 Stream 中元素做彙總的方法
*/
public class TestStream04 {
List<Employee> employees = Arrays.asList(
new Employee(1, "atom", Employee.Status.BUSY),
new Employee(2, "jashon", Employee.Status.FREE),
new Employee(3, "Linus", Employee.Status.VOCATION),
new Employee(4, "henry", Employee.Status.FREE),
new Employee(4, "cenry", Employee.Status.VOCATION),
new Employee(4, "zenry", Employee.Status.BUSY),
new Employee(3, "Jack", Employee.Status.BUSY)
);
@Test
public void test8() {
String str = employees.stream().map(Employee::getName)
.collect(Collectors.joining(",", "-> ", " <-"));
// .collect(Collectors.joining(","));
System.out.println(str);
}
@Test
public void test7() {
// 此方法可獲得 test3 中所計算的值
IntSummaryStatistics iss = employees.stream().collect(Collectors.summarizingInt(Employee::getId));
System.out.println(iss.getAverage());
System.out.println(iss.getCount());
System.out.println(iss.getCount());
System.out.println(iss.getMax());
System.out.println(iss.getMin());
}
@Test
public void test6() {
Map<Boolean, List<Employee>> map = employees.stream()
.collect(Collectors.partitioningBy((e) -> e.getId() > 3));
System.out.println(map);
}
// 多級分組
@Test
public void test5() {
Map<Employee.Status, Map<String, List<Employee>>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if(((Employee) e).getId() < 3) {
return "靠前";
} else {
return "靠後";
}
})));
System.out.println(map);
}
// 分組
@Test
public void test4() {
Map<Employee.Status, List<Employee>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
}
// 計算
@Test
public void test3() {
// 總數
long count = employees.stream()
.collect(Collectors.counting());
System.out.println("total:" + count);
System.out.println("=======================");
// 平均值
Double avg = employees.stream()
.collect(Collectors.averagingDouble(Employee::getId));
System.out.println("avg:" + avg);
System.out.println("=======================");
// 總和
Integer sum = employees.stream()
.collect(Collectors.summingInt(Employee::getId));
System.out.println("sum:" + sum);
System.out.println("=======================");
// 最大值的對象
Optional<Employee> max = employees.stream()
.collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getId(), e2.getId())));
System.out.println("最大值: " + max.get());
System.out.println("=======================");
// 最小值
Optional<Integer> min = employees.stream()
.map(Employee::getId)
.collect(Collectors.minBy(Integer::compare));
System.out.println("最小值: " + min.get());
}
// 收集獲得集合
@Test
public void test2() {
List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("=======================");
Set<String> set = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
set.forEach(System.out::println);
}
}