Stream是Java8中處理集合的關鍵抽象概念,它能夠指定你但願對集合進行的操做,能夠執行很是複雜的查找、過濾和映射數據等操做。使用Stream API對集合進行操做,就相似與使用SQL執行的數據庫操做。也可使用Stream API來並行執行操做。簡而言之,Stream API 提供了一種高效且易於使用的處理數據的方式。數據庫
是數據渠道,用於操做數據源(集合、數組等)所生成的元素序列
集合講的是數據,流講的是計算數組
PS:dom
下面的圖能夠比較直觀的反映這一過程:
ide
Java8中的Collection接口被擴展,提供了兩個獲取流的方法:函數
- default Stream
stream():返回一個順序流 - default Stream
parallelStream():返回一個並行流
示例代碼:測試
List<Integer> list = new ArrayList<>(); Stream<Integer> stream1 = list.stream(); Stream<Integer> stream2 = list.parallelStream();
Java8的Arrays的靜態方法stream()能夠獲取數據流this
- static
Stream stream(T[] arrays):返回一個流
示例代碼:code
Integer[] integers = new Integer[10]; Stream<Integer> stream = Arrays.stream(integers);
經過Stream類中的靜態方法of(),經過顯示值建立一個流,能夠接收任意數量的參數對象
- public static
Stream of(T ... values):返回一個流
示例代碼:blog
Stream<Integer> stream = Stream.of(1, 2, 3);
使用靜態方法Stream.iterate()和Stream.generate(),建立無限流
- 迭代:public static
Stream iterate(final T seed, final UnaryOperator f) - 生成:public static
Stream generate(Supplier s)
示例代碼:
// 迭代 Stream stream1 = Stream.iterate(0, (x) -> x + 2); // 生成 Stream stream2 = Stream.generate(() -> Math.random());
多個中間操做能夠鏈接起來造成一個流水線,除非流水線上觸發終止操做,不然中間操做不會執行任何的處理!而在終止操做時一次性所有處理,稱之爲「惰性求值」。
- filter:結合搜lambda,從流中排除元素
- limit:截斷流,使其元素不超過給定數量
- skip(n):跳過元素,返回一個刪除了前n個元素的流;若流中元素不足n個,則返回一個空流;與limit(n)互補
- distinct:篩選,經過流所生成的元素的hashCode()和equals()去除重複元素
示例代碼:
public class TestStreamApi { private static List<Demo> demoList = Arrays.asList( new Demo(1, "哈哈哈"), new Demo(2, "嘿嘿嘿嘿"), new Demo(3, "呵呵呵"), new Demo(4, "恩恩恩恩"), new Demo(5, "哼哼哼"), new Demo(6, "嘖嘖嘖"), new Demo(5, "哼哼哼"), new Demo(8, "哼") ); public static void main(String[] args) { // 中間操做不會執行任何操做 Stream<Demo> demoStream = demoList.stream() .filter((x) -> x.getRemark().length() == 3) .limit(4) .skip(1) .distinct(); // 終止操做一次性執行所有內容 // 內部迭代:迭代操做由Stream API完成 demoStream.forEach(System.out::println); } }
運行結果:
3-呵呵呵
5-哼哼哼
6-嘖嘖嘖
注意:distinct篩選經過流所生成的元素的hashCode()和equals()去除重複元素,因此須要重寫Demo的hashCode()和equals()方法。
- map:接收Lambda,將元素轉換成其它形式或提取信息;接收一個函數做爲參數,該函數會被應用到每一個元素上,並將其映射成一個新的元素
- flatMap:接收一個函數做爲參數,將流中的每一個值都換成另外一個流,而後把全部的流鏈接成一個流
示例代碼:
public class TestStreamApi { private static List<Demo> demoList = Arrays.asList( new Demo(1, "哈哈哈"), new Demo(2, "嘿嘿嘿嘿") ); public static void main(String[] args) { demoList.stream() .map(Demo::getRemark) .flatMap(TestStreamApi :: filterCharacter) .forEach(System.out::println); } public static Stream<Character> filterCharacter(String str) { List<Character> list = new ArrayList<>(); for (Character c : str.toCharArray()) { list.add(c); } return list.stream(); } }
運行結果:
哈
哈
哈
嘿
嘿
嘿
嘿
- sorted():天然排序
- sorted(Comparator c):定製排序
示例代碼:
public class TestStreamApi { private static List<Demo> demoList = Arrays.asList( new Demo(5, "哈哈哈"), new Demo(2, "嘿嘿嘿嘿"), new Demo(3, "呵呵呵"), new Demo(2, "哼哼哼"), new Demo(5, "嘖嘖嘖") ); public static void main(String[] args) { List<String> list = Arrays.asList("aaa", "bbb", "ccc"); list.stream() .sorted() .forEach(System.out::println); System.out.println("----------"); demoList.stream() .sorted((x, y) -> { if (x.getNum().equals(y.getNum())) { return x.getRemark().compareTo(y.getRemark()); } else { return x.getNum().compareTo(y.getNum()); } }) .forEach(System.out::println); } }
運行結果:
aaa
bbb
ccc
----------
2-哼哼哼
2-嘿嘿嘿嘿
3-呵呵呵
5-哈哈哈
5-嘖嘖嘖
- allMatch:檢查是否匹配全部元素
- anyMatch:檢查是否匹配全部元素
- noneMatch:檢查是否沒有匹配全部元素
- findFirst:返回第一個元素
- findAny:返回當前流中的任意元素
- count:返回流中元素的總個數
- max:返回流中的最大值
- min:返回流中的最小值
示例代碼:
public class TestStreamApi2 { private static List<Demo> demoList = Arrays.asList( new Demo("張三", 18, 6666.66, Demo.Status.BUSY), new Demo("李四", 38, 3333.33, Demo.Status.FREE), new Demo("王五", 28, 5555.55, Demo.Status.FREE), new Demo("趙六", 48, 7777.77, Demo.Status.BUSY), new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION) ); public static void main(String[] args) { // 是否是全部的對象都處於BUSY狀態 System.out.println(demoList.stream() .allMatch((d) -> d.getStatus().equals(Demo.Status.BUSY))); // 是否有對象處於BUSY狀態 System.out.println(demoList.stream() .anyMatch((d) -> d.getStatus().equals(Demo.Status.BUSY))); // 是否沒有對象處於BUSY狀態 System.out.println(demoList.stream() .noneMatch((d) -> d.getStatus().equals(Demo.Status.BUSY))); // 獲取工資最高的 Optional<Demo> optionalDemo1 = demoList.stream() .sorted((x, y) -> -Double.compare(x.getSalary(), y.getSalary())) .findFirst(); System.out.println(optionalDemo1.get()); // 獲取隨機一個空閒的 Optional<Demo> optionalDemo2 = demoList.stream() .filter((e) -> e.getStatus().equals(Demo.Status.FREE)) .findAny(); System.out.println(optionalDemo2.get()); // 總數 System.out.println(demoList.stream().count()); // 工資最高的 Optional<Demo> optionalDemo3 = demoList.stream() .max((x, y) -> Double.compare(x.getSalary(), y.getSalary())); System.out.println(optionalDemo3.get()); // 最小的工資 Optional<Double> optionalDemo4 = demoList.stream() .map(Demo::getSalary) .max(Double::compare); System.out.println(optionalDemo4.get()); } } class Demo{ // 姓名 String name; // 年齡 Integer age; // 工資 Double salary; // 狀態 Status status; public Demo() {} public Demo(String name, Integer age, Double salary, Status status) { this.name = name; this.age = age; this.salary = salary; this.status = status; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Demo demo = (Demo) o; return name.equals(demo.name) && age.equals(demo.age) && salary.equals(demo.salary) && status == demo.status; } @Override public int hashCode() { return Objects.hash(name, age, salary, status); } @Override public String toString() { return "Demo{" + "name='" + name + '\'' + ", age=" + age + ", salary=" + salary + ", status=" + status + '}'; } public enum Status{ FREE, BUSY, VOCATION } }
運行結果:
false
true
false
Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}
Demo{name='李四', age=38, salary=3333.33, status=FREE}
5
Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}
8888.88
- reduce(T identify, BinaryOperator) / reduce(BinaryOperator):能夠將流中元素反覆結合起來,獲得一個值
示例代碼:
public class TestStreamApi3 { private static List<Demo> demoList = Arrays.asList( new Demo("張三", 18, 6666.66, Demo.Status.BUSY), new Demo("李四", 38, 3333.33, Demo.Status.FREE), new Demo("王五", 28, 5555.55, Demo.Status.FREE), new Demo("趙六", 48, 7777.77, Demo.Status.BUSY), new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION) ); public static void main(String[] args) { Optional<Double> optional = demoList.stream() .map(Demo::getSalary) .reduce(Double::sum); System.out.println(optional.get()); } }
運行結果:
32222.190000000002
- collect:將流轉換爲其餘形式。接收一個Collection接口的實現,用於給Stream中元素作彙總的方法
Collectors接口中方法的實現決定了如何對流執行收集操做(如蒐集到List、Set、Map)。
- toList:把流中元素收集到List
- toSet:把流中元素收集到Set
- toCollection:把流中元素收集到建立的集合
- counting:計算流中元素的個數
- summingInt:對流中元素的整數屬性求和
- averagingInt:計算流中元素Integer屬性的平均值
- summarizingInt:收集流中Integer屬性的統計值
- jioning:鏈接流中的每一個字符串
- maxBy:根據比較器選擇最大值
- minBy:根據比較器選擇最小值
- reducing:從一個做爲累加器的初始值開始,利用BinaryOperator與流中元素逐個結合,從而規約成單個值
- collectingAndThen:包裹另外一個收集器,對其結果轉換函數
- groupingBy:根據某個屬性值對流分組,屬性爲K,結果爲V
- partitioningBy:根據true、false進行分區
給定一個數組,方便測試:
private static List<Demo> demoList = Arrays.asList( new Demo("張三", 18, 6666.66, Demo.Status.BUSY), new Demo("李四", 38, 3333.33, Demo.Status.FREE), new Demo("王五", 28, 5555.55, Demo.Status.FREE), new Demo("趙六", 48, 7777.77, Demo.Status.BUSY), new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION) );
示例代碼:
// 收集 - toList System.out.println("---------------->toList"); List<String> list = demoList.stream() .map(Demo::getName) .collect(Collectors.toList()); list.forEach(System.out::println);
運行結果:
張三
李四
王五
趙六
王二麻子
示例代碼:
// 收集 - toSet System.out.println("---------------->toSet"); Set<String> set = demoList.stream() .map(Demo::getName) .collect(Collectors.toSet()); set.forEach(System.out::println);
運行結果:
李四
張三
王二麻子
王五
趙六
示例代碼:
// 收集 - toCollection System.out.println("---------------->toCollection"); HashSet<String> hashSet = demoList.stream() .map(Demo::getName) .collect(Collectors.toCollection(HashSet::new)); hashSet.forEach(System.out::println);
運行結果:
李四
張三
王二麻子
王五
趙六
示例代碼:
// 收集 - counting 計算總數 System.out.println("---------------->counting"); System.out.println(demoList.stream() .collect(Collectors.counting()));
運行結果:
5
示例代碼:
// 收集 - summingInt 計算年齡總和 System.out.println("---------------->summingInt"); System.out.println(demoList.stream() .collect(Collectors.summingInt(Demo::getAge)));
運行結果:
190
示例代碼:
// 收集 - averagingInt 平均年齡 System.out.println("---------------->averagingInt"); System.out.println(demoList.stream() .collect(Collectors.averagingInt(Demo::getAge)));
運行結果:
38.0
示例代碼:
// 收集 - summarizingInt System.out.println("---------------->summarizingInt"); IntSummaryStatistics summaryStatistics = demoList.stream() .collect(Collectors.summarizingInt(Demo::getAge)); // 最大值 System.out.println(summaryStatistics.getMax()); // 平均值 System.out.println(summaryStatistics.getAverage()); // 總和 System.out.println(summaryStatistics.getSum());
運行結果:
58
38.0
190
示例代碼:
// 收集 - joining 鏈接姓名 System.out.println("---------------->joining"); String s = demoList.stream() .map(Demo::getName) .collect(Collectors.joining(",", "開始->", "<-結束")); System.out.println(s);
運行結果:
開始->張三,李四,王五,趙六,王二麻子<-結束
示例代碼:
// 收集 - maxBy 獲取工資最高的人 System.out.println("---------------->maxBy"); Optional<Demo> max = demoList.stream() .collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary()))); System.out.println(max.get());
運行結果:
Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}
示例代碼:
// 收集 - minBy 獲取最低的 System.out.println("---------------->minBy"); Optional<Double> min = demoList.stream() .map(Demo::getSalary) .collect(Collectors.minBy(Double::compare)); System.out.println(min.get());
運行結果:
3333.33
示例代碼:
// 收集 - groupingBy 根據狀態分組 System.out.println("---------------->groupingBy"); Map<Demo.Status, List<Demo>> group = demoList.stream() .collect(Collectors.groupingBy(Demo::getStatus)); System.out.println(group); // 多級分組 先按狀態分組,在按年齡分組 Map<Demo.Status, Map<String, List<Demo>>> group2 = demoList.stream() .collect(Collectors.groupingBy(Demo::getStatus, Collectors.groupingBy((x) -> { if (x.getAge() <= 30) { return "青年"; } else if (x.getAge() <= 45) { return "中年"; } else { return "老年"; } }))); System.out.println(group2);
運行結果:
{VOCATION=[Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}], FREE=[Demo{name='李四', age=38, salary=3333.33, status=FREE}, Demo{name='王五', age=28, salary=5555.55, status=FREE}], BUSY=[Demo{name='張三', age=18, salary=6666.66, status=BUSY}, Demo{name='趙六', age=48, salary=7777.77, status=BUSY}]}
{VOCATION={老年=[Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}]}, FREE={青年=[Demo{name='王五', age=28, salary=5555.55, status=FREE}], 中年=[Demo{name='李四', age=38, salary=3333.33, status=FREE}]}, BUSY={青年=[Demo{name='張三', age=18, salary=6666.66, status=BUSY}], 老年=[Demo{name='趙六', age=48, salary=7777.77, status=BUSY}]}}
示例代碼:
// 收集 - partitioningBy 分區 System.out.println("---------------->partitioningBy"); Map<Boolean, List<Demo>> partition = demoList.stream() .collect(Collectors.partitioningBy((x) -> x.getAge() > 30)); System.out.println(partition);
運行結果: {false=[Demo{name='張三', age=18, salary=6666.66, status=BUSY}, Demo{name='王五', age=28, salary=5555.55, status=FREE}], true=[Demo{name='李四', age=38, salary=3333.33, status=FREE}, Demo{name='趙六', age=48, salary=7777.77, status=BUSY}, Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}]}