stream of java_java8新特性之强大的Stream API
Stream API
Stream是Java8中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常復雜的查找、過濾和映射數據等操作。
使用Stream API 對集合數據進行操作,就類似于使用 SQL 執行的數 據庫查詢。
也可以使用Stream API來并行執行操作。
簡而言之,Stream API 提供了一種高效且易于使用的處理數據的方式。
流(Stream) 到底是什么呢?
Stream流是數據渠道,用于操作數據源(集合、數組等)所生成的元素序列,以下三點注意。
Stream 自己不會存儲元素。
Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。
Stream 操作是延遲執行的。這意味著他們會等到需要結果的時候才執行。
Stream流操作的三大步
創建Stream流 //一個數據源 集合/數組/Stream靜態方法 獲取一個Stream流
中間操作 //對數據源的數據進行處理,過濾,篩選等等
終止操作 //執行中間操作鏈,產生結果
創建Stream流
1.集合創建Stream流
/****
* java8中的Collection接口方法
* stream() 順序流
* parallelStream() 并行流(后面再說這個)
*/
@Test
public void test01() {
//聲明一個list
List list = new ArrayList();
// default Stream stream() 順序流
// default Stream parallelStream() 并行流
// 創建一個順序流
Stream stream1 = list.stream();
// 創建一個并行流
Stream stream2 = list.parallelStream();
}
2.數組創建Stream流
/****
* 數組創建Stream流
* Java8 中的 Arrays 的靜態方法 stream() 可以獲取數組流
*/
@Test
public void test02() {
// Java8 中的 Arrays 的靜態方法 stream() 可以獲取數組流
// public static Stream stream(T[] array)
String[] arr = new String[10];
Stream stream = Arrays.stream(arr);
}
3.由值創建Stream流 Stream.of()
/****
* 由值創建Stream流
* Stream.of()
*/
@Test
public void test03() {
// 可以使用靜態方法 Stream.of(), 通過顯式值創建一個流。它可以接收任意數量的參數。
Stream stream = Stream.of("1", "2", "3", "4");
}
4.由函數創建Stream無限流 iterate.generate() Stream.generate()
/****
* 由函數創建Stream無限流
*
* seed種子 f 一元運算接口
* Stream.iterate(T seed,UnaryOperator f)
*
* supplier 供給型型接口
* Stream.generate(Supplier supplier)
*/
@Test
public void test04() {
// 可以使用靜態方法 Stream.iterate() 和 Stream.generate(), 創建無限流。
// args1 seed 開始種子, args2 一元函數式接口
//迭代 public static Stream iterate(final T seed, final UnaryOperator f)
Stream stream1 = Stream.iterate(0, (x) -> x + 1);
//args 一個供給型接口
// 生成 public static Stream generate(Supplier s) :
Stream stream2 = Stream.generate(() -> new Random().nextInt(100));
}
Stream流中間操作
多個中間操作可以連接起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理,而在終止操作時一次性全部處理,稱為“惰性求值”。看一下一些常用的api:
1.流中排除不符合條件的元素:filter
/****
* filter(Predicate p)
* 接收一個斷言式接口,從流中排除不符合條件的元素
*/
@Test
public void test01() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//使用Stream流的靜態方法 of創建一個Stream流
Stream stream = Stream.of(nums);
//過濾操作 接收一個斷言式接口 排除不符合條件的元素 輸出結果
stream.filter((x) -> x > 5).forEach(System.out::println);
}
2.流中去除重復元素:distinct
/***
* distinct()
* 篩選,通過流所生成元素的 hashCode() 和 equals() 去除重復元素
*/
@Test
public void test02() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
//使用Stream流的靜態方法 of創建一個Stream流
Stream stream = Stream.of(nums);
//去除重復的元素
stream.distinct().forEach(System.out::println);
}
3.截取流獲取前n個元素:limit
/***
* limit(long maxSize)
* 接收一個long型數值流中的元素個數不操過maxSize個,
*/
@Test
public void test03() {
//使用Stream流的靜態方法 generate創建一個Stream無限流
Stream stream = Stream.generate(() -> new Random().nextInt(100));
//截斷流獲取前n個元素 最大n個
stream.limit(10).forEach(System.out::println);
}
4.跳過流前n個元素:skip
/***
* skip(long n)
* 接收一個long型數值 跳過流前n個元素獲取后面的元素和 limit(n)相反
*/
@Test
public void test04() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
//使用Stream流的靜態方法 generate創建一個Stream無限流
Stream stream = Arrays.stream(nums);
stream.skip(3).forEach(System.out::println);
}
5.映射流中的每一個元素:map
/****
* map(Function f)
* 接收一個函數作為參數,該函數會被應用到每個元素上,并將其映射成一個新的元素。
*/
@Test
public void test05() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//使用Stream流的靜態方法 generate創建一個Stream無限流
Stream stream = Arrays.stream(nums);
// 將每個元素*2
stream.map(x -> x * 2).forEach(System.out::println);
}
6.將流中元素映射成一個新的Double型元素:mapToDouble
/****
* mapToDouble(ToDoubleFunction f)
* 接收一個函數作為參數,該函數會被應用到每個元素上,并將其映射成一個新的Double型元素。
* 注意原數組要可以轉換成Double型
*/
@Test
public void test06() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//使用Stream流的靜態方法 generate創建一個Stream無限流
Stream stream = Arrays.stream(nums);
// 將每個元素 變成double
stream.mapToDouble(x -> x * 2).forEach(System.out::println);
}
7.將流中元素映射成一個新的Long型元素:mapToDouble
/****
* mapToLong(ToDoubleFunction f)
* 接收一個函數作為參數,該函數會被應用到每個元素上,并將其映射成一個新的Long型元素。
* 注意原數組要可以轉換成Long型
*/
@Test
public void test07() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//使用Stream流的靜態方法 generate創建一個Stream無限流
Stream stream = Arrays.stream(nums);
// 將每個元素 變成double
stream.mapToDouble(x -> x * 2).forEach(System.out::println);
}
8.將流中的每個值都換成另一個流,然后把所有流連接成一個流:flatMap
/****
* flatMap(ToDoubleFunction f)
* 接收一個函數作為參數,將流中的每個值都換成另一個流,然后把所有流連接成一個流
*/
@Test
public void test08() {
String[] strings = {"hello lambda", "hello", "lambda"};
// Stream的靜態方法 of獲取流
Stream testStream = Stream.of(strings);
// 流中的元素換成另一個流 分割處理 然后去重 打印
testStream.flatMap(str -> Arrays.stream(str.split(" "))).distinct().forEach(System.out::println);
}
9.產生一個新流,其中按自然順序排序:sorted
/**
* sorted()
* 產生一個新流,其中按自然順序排序
*/
@Test
public void test09() {
Integer[] nums = {1, 4, 2, 6, 3, 0, 9, 8, 7, 5};
Arrays.stream(nums).sorted().forEach(System.out::println);
}
10.產生一個新流,其中按比較器順序排序:sorted
/**
* sorted(Comparator comparator)
* 產生一個新流,其中按比較器順序排序
*/
@Test
public void test10() {
Integer[] nums = {-1, 4, -2, 6, -3, 0, 9, -8, 7, -5};
//例如 按照絕對值排序
Arrays.stream(nums).sorted(Comparator.comparing(x -> Math.abs(x))).forEach(System.out::println);
}
Stream流的終止操作
終端操作會從流的流水線生成結果。 其結果可以是任何不是流的值,例如:List、Integer、boolean
1.判斷流中的元素是否全部滿足某一個條件:allMatch
/****
* allMatch(Predicate predicate)
* 接收一個斷言式接口 全匹配 返回boolean
*/
@Test
public void test01() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//使用Stream流的靜態方法 of創建一個Stream流
Stream stream = Stream.of(nums);
// 匹配數組元素是否全部大于等于0
System.out.println(stream.allMatch((x) -> x >= 0));
}
2.判斷流中的元素至少滿足某一個條件:anyMatch
/****
* anyMatch(Predicate predicate)
* 接收一個斷言式接口 至少匹配一個 返回boolean
*/
@Test
public void test02() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//使用Stream流的靜態方法 of創建一個Stream流
Stream stream = Stream.of(nums);
// 匹配數組元素是否有大于10的元素
System.out.println(stream.anyMatch((x) -> x > 10));
}
3.判斷流中的元素都不滿足某一個條件:noneMatch
/****
* noneMatch(Predicate predicate)
* 接收一個斷言式接口 是否沒有匹配的元素 返回boolean
*/
@Test
public void test03() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//使用Stream流的靜態方法 of創建一個Stream流
Stream stream = Stream.of(nums);
// 匹配數組元素是否沒有大于10的元素
System.out.println(stream.noneMatch((x) -> x > 10));
}
4.返回流元素中的第一個元素:findFirst
/****
* findFirst()
* 返回Optional
*/
@Test
public void test04() {
Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
//使用數組Arrays創建流
Stream stream = Arrays.stream(nums);
//返回流元素中的第一個元素
Optional optional = stream.findFirst();
System.out.println(optional.get());
}
5.返回流元素中的任意一個元素:findAny
/****
* findAny()
* 返回Optional
*/
@Test
public void test05() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
//使用數組Arrays創建流
Stream stream = Arrays.stream(nums);
//返回流元素中的任意元素
Optional optional = stream.findAny();
System.out.println(optional.get());
}
6.返回流元素總數:count
/****
* count()
* 返回流元素總數 Long型
*/
@Test
public void test06() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
//使用數組Arrays創建流
Stream stream = Arrays.stream(nums);
Long aLong = stream.count();
System.out.println(aLong);
}
7.返回流元素中的最大元素:max
/****
* max(Comparator comparator)
* 返回流元素最大值
* 接收一個比較器
*/
@Test
public void test07() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
//使用數組Arrays創建流
Stream stream = Arrays.stream(nums);
//返回流元素中的最大元素
Optional optional = stream.max(Integer::compare);
System.out.println(optional.get());
}
8.返回流元素中的最小元素:min
/****
* max(Comparator comparator)
* 返回流元素最小值
* 接收一個比較器
*/
@Test
public void test08() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
//使用數組Arrays創建流
Stream stream = Arrays.stream(nums);
//返回流元素中的最小元素
Optional optional = stream.min(Integer::compare);
System.out.println(optional.get());
}
9.內部迭代:forEach
/****
* forEach(Consumer consumer)
* 接收一個消費性接口
* 內部迭代(使用 Collection 接口需要用戶去做迭代,稱為外部迭代。
* 相反,Stream API 使用內部 迭代——它幫你把迭代做了)
*/
@Test
public void test09() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
Arrays.stream(nums).forEach(System.out::println);
}
10.將流中元素反復結合起來,得到一個值:reduce
/***
* reduce(BinaryOperator accumulator)
* 可以將流中元素反復結合起來,得到一個值。返回Optional
* 接收一個二元運算接口
*/
@Test
public void test10() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
// 依次累加
Object object = Arrays.stream(nums).reduce((x, y) -> x + y).get();
System.out.println(object);
}
11.將流中元素反復結合起來(有一個起始值),得到一個值:reduce
/***
* reduce(T iden, BinaryOperator accumulator)
* 接收一個二元運算接口
* 可以將流中元素反復結合起來,得到一個值。返回 T
*/
@Test
public void test11() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
// iden 作為一個值先加入運算然后 依次累加
Object object = Arrays.stream(nums).reduce(10, (x, y) -> x * y);
System.out.println(object);
}
12.將流轉換為List:stream.collect(Collectors.toList())
/***
* collect(Collector collector)
* 將流轉換為其他形式。
* 接收一個 Collector接口的實現,用于給Stream中元素做匯總的方法
* Collectors 實用類提供了很多靜態方法,可以方便地創建常見收集器實例
* Collectors.toList()
* // 將數組變成了 list
*/
@Test
public void test12() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
Stream stream = Arrays.stream(nums);
List list = stream.collect(Collectors.toList());
// 將數組變成了 list
System.out.println(list.size());
}
13.將流轉換為Set:stream.collect(Collectors.toSet())
/***
* Collectors.toSet()
* 將數組變成了 set
*/
@Test
public void test13() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
Stream stream = Arrays.stream(nums);
Set set = stream.collect(Collectors.toSet());
// 將數組變成了 set
System.out.println(set.size());
}
14.將流轉換為Collection:stream.collect(Collectors.toSet())
/***
* Collectors.toCollection(ArrayList::new)
* Collectors.toCollection(HashSet::new)
* 將數組變成了 Collection
*/
@Test
public void test14() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
Stream stream = Arrays.stream(nums);
Collection collection = stream.collect(Collectors.toCollection(HashSet::new));
// 將數組變成了 collection
System.out.println(collection.size());
}
15.計算流中元素的個數:stream.collect(Collectors.counting())
/***
* Collectors.counting()
* 計算流中元素的個數
*/
@Test
public void test15() {
Integer[] nums = {2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1};
Stream stream = Arrays.stream(nums);
Long integer = stream.collect(Collectors.counting());
System.out.println(integer);
}
16.計算流中元素的對象的某一個屬性平均值:stream.collect(Collectors.summingDouble())
/***
* Collectors.summingDouble(ToDoubleFunction mapper)
* 計算流中元素的對象的某一個屬性平均值
* 接收一個 計算int、long、 double、值的函數 接口
*/
@Test
public void test16() {
List employees = new ArrayList<>(3);
Employee employe1 = new Employee(1, "A1", 5000);
Employee employe2 = new Employee(1, "A2", 8000);
Employee employe3 = new Employee(1, "A3", 10000);
employees.add(employe1);
employees.add(employe2);
employees.add(employe3);
Stream stream = employees.stream();
Double sumSalary = stream.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sumSalary);
}
17.計算流中元素的對象的某一個屬性平均值:stream.collect(Collectors.averagingDouble())
/***
* Collectors.averagingDouble(ToDoubleFunction mapper)
* 計算流中元素的對象的某一個屬性平均值
* 接收一個 計算int、long、 double、值的函數 接口
*/
@Test
public void test17() {
List employees = new ArrayList<>(3);
Employee employe1 = new Employee(1, "A1", 5000);
Employee employe2 = new Employee(1, "A2", 8000);
Employee employe3 = new Employee(1, "A3", 10000);
employees.add(employe1);
employees.add(employe2);
employees.add(employe3);
Stream stream = employees.stream();
Double avgSalary = stream.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avgSalary);
}
18.連接流中元素的對象的某一個屬性字符串:stream.collect(Collectors.joining())
/***
* Collectors.joining()
* 連接流中元素的對象的某一個屬性字符串
*/
@Test
public void test18() {
List employees = new ArrayList<>(3);
Employee employe1 = new Employee(1, "A1", 5000);
Employee employe2 = new Employee(1, "A2", 8000);
Employee employe3 = new Employee(1, "A3", 10000);
employees.add(employe1);
employees.add(employe2);
employees.add(employe3);
Stream stream = employees.stream();
String names = stream.map((x) -> x.getName() + "-").collect(Collectors.joining());
System.out.println(names);
}
19.收集器中最小值:stream.collect(Collectors.minBy())
/***
* Collectors.maxBy(Comparator comparator)
* 根據比較器選擇最小值
* 接收一個比較器
*/
@Test
public void test19() {
Integer[] nums = {1, 2, 3, 4, 5, 7, 8, 9, 3, 4, 56};
Stream stream = Arrays.stream(nums);
Optional optional = stream.collect(Collectors.minBy(Integer::compareTo));
System.out.println(optional.get());
}
20.收集器中某一屬性之和:stream.collect(Collectors.reducing())
/***
* Collectors.reducing(U identity,Function super T, ? extends U> mapper,BinaryOperator op)
* 從一個作為累加器的初始值開始,利用BinaryOperator與流中元素逐個結合,從而歸約成單個值
* 接收二元計算接口
*/
@Test
public void test20() {
List employees = new ArrayList<>(3);
Employee employe1 = new Employee(1, "A1", 5000);
Employee employe2 = new Employee(1, "A2", 8000);
Employee employe3 = new Employee(1, "A3", 10000);
employees.add(employe1);
employees.add(employe2);
employees.add(employe3);
Stream stream = employees.stream();
// identity : 0d 類型和后面的元素類型 保持一致
Double aDouble = stream.collect(Collectors.reducing(0d, Employee::getSalary, Double::sum));
System.out.println(aDouble);
}
21.收集器轉換為另一類型然后處理:stream.collect(Collectors.collectingAndThen())
/***
* Collectors.collectingAndThen(Collector downstream,Function finisher)
* 轉換函數返回的類型
* 包裹另一個收集器,對其結果轉換函數
*/
@Test
public void test21() {
List employees = new ArrayList<>(3);
Employee employe1 = new Employee(1, "A1", 5000);
Employee employe2 = new Employee(1, "A2", 8000);
Employee employe3 = new Employee(1, "A3", 10000);
employees.add(employe1);
employees.add(employe2);
employees.add(employe3);
Stream stream = employees.stream();
// 轉換函數返回的類型 返回set
// 包裹另一個收集器,對其結果 set 進行處理 判斷時候為空
Boolean bool = stream.collect(Collectors.collectingAndThen(Collectors.toSet(), Set::isEmpty));
System.out.println(bool);
}
22.收集器按照某一屬性分組:stream.collect(Collectors.groupingBy())
/***
* 根據某屬性值對流分組,屬 性為K,結果為V
* Collectors.groupingBy(Function super T, ? extends K> classifier)
* 傳入一個 代表流元素的屬性
* 返回 以屬性為key value為 list的map
*/
@Test
public void test22() {
List employees = new ArrayList<>(3);
Employee employe1 = new Employee(1, "A1", 5000);
Employee employe2 = new Employee(1, "A2", 8000);
Employee employe3 = new Employee(1, "A3", 10000);
employees.add(employe1);
employees.add(employe2);
employees.add(employe3);
Stream stream = employees.stream();
Map map = stream.collect(Collectors.groupingBy(Employee::getName));
Set set=map.entrySet();
for (Object str:set) {
System.out.println(str);
System.out.println(map.get(str));
}
}
23.收集器按照某一屬性(boolean類型)分組:stream.collect(Collectors.partitioningBy())
/***
* 根據true或false進行分區
* Collectors.groupingBy(Function super T, ? extends K> classifier)
* 傳入一個 代表流元素的屬性
* 返回 以屬性(flase/true)為key value為 list的map
*/
@Test
public void test23() {
List employees = new ArrayList<>(3);
Employee employe1 = new Employee(1, "A1", 5000,false);
Employee employe2 = new Employee(1, "A2", 8000,true);
Employee employe3 = new Employee(1, "A3", 10000,false);
employees.add(employe1);
employees.add(employe2);
employees.add(employe3);
Stream stream = employees.stream();
Map map = stream.collect(Collectors.partitioningBy(Employee::getFlag));
Set set=map.entrySet();
for (Object str:set) {
System.out.println(str);
System.out.println(map.get(str));
}
}
輔助類Employee
/**
* @author black貓
* @date 2019-11-25
* 員工類
*/
public class Employee {
private int id;
private String name;
private double salary;
private boolean flag;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public boolean getFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public Employee(int id, String name, double salary){
this.id=id;
this.name=name;
this.salary=salary;
}
public Employee(int id, String name, double salary,boolean flag){
this.id=id;
this.name=name;
this.salary=salary;
this.flag=flag;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", salary=" + salary +
", flag=" + flag +
'}';
}
}
我的小結
Stream是java8提供的java.util.stream.*包下的強大Api,結合lambda表達式,可以快速、高效、便捷的對集合數據進行處理, 熟練掌握之后,就像寫sql一樣操作集合數據,功能強大,代碼不再那么臃腫、冗余。爽!!!
文章首發于黑貓のBlog歡迎來留言啊!!!
總結
以上是生活随笔為你收集整理的stream of java_java8新特性之强大的Stream API的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bcp 不能调用where 子句_技术分
- 下一篇: 【LeetCode笔记】51. N 皇后