一.概念
Stream是一種可供流式操作的數據視圖有些類似數據庫中視圖的概念它不改變源數據集合如果對其進行改變的操作它會返回一個新的數據集合。
總的來講它有三大特性:在之后我們會對照着詳細說明
1、stream不存儲數據
2、stream不改變源數據
3、stream的延遲執行特性
二.優點
1、代碼簡潔,函數式編程寫出的代碼簡潔且意圖明確,使用stream接口讓你從此告別for循環。
2、多核友好,Java函數式編程使得編寫並行程序從未如此簡單,你需要的全部就是調用一下parallel()
方法。
三.Stream API常用方法
Stream操作分類 | ||
---|---|---|
中間操作(Intermediate operations) | 無狀態(Stateless) | unordered() filter() map() mapToInt() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() peek() |
有狀態(Stateful) | distinct() sorted() sorted() limit() skip() | |
結束操作(Terminal operations) | 非短路操作 | forEach() forEachOrdered() toArray() reduce() collect() max() min() count() |
短路操作(short-circuiting) | anyMatch() allMatch() noneMatch() findFirst() findAny() |
Stream上的所有操作分為兩類:中間操作和結束操作,中間操作只是一種標記,只有結束操作才會觸發實際計算。
中間操作又可以分為無狀態的和有狀態的:
無狀態中間操作是指元素的處理不受前面元素的影響,而有狀態的中間操作必須等到所有元素處理之后才知道最終結果,比如排序是有狀態操作,在讀取所有元素之前並不能確定排序結果;
結束操作又可以分為短路操作和非短路操作
短路操作是指不用處理全部元素就可以返回結果,比如找到第一個滿足條件的元素。之所以要進行如此精細的划分,是因為底層對每一種情況的處理方式不同。
常用中間件
filter:過濾流,過濾流中的元素,返回一個符合條件的Stream
map:轉換流,將一種類型的流轉換為另外一種流。(mapToInt、mapToLong、mapToDouble 返回int、long、double基本類型對應的Stream)
flatMap:簡單的說,就是一個或多個流合並成一個新流。(flatMapToInt、flatMapToLong、flatMapToDouble 返回對應的IntStream、LongStream、DoubleStream流。)
distinct:返回去重的Stream。
sorted:返回一個排序的Stream。
peek:主要用來查看流中元素的數據狀態。
limit:返回前n個元素數據組成的Stream。屬於短路操作
skip:返回第n個元素后面數據組成的Stream。
結束操作
forEach: 循環操作Stream中數據。
toArray: 返回流中元素對應的數組對象。
reduce: 聚合操作,用來做統計。
collect: 聚合操作,封裝目標數據。
min、max、count: 聚合操作,最小值,最大值,總數量。
anyMatch: 短路操作,有一個符合條件返回true。
allMatch: 所有數據都符合條件返回true。
noneMatch: 所有數據都不符合條件返回true。
findFirst: 短路操作,獲取第一個元素。
findAny: 短路操作,獲取任一元素。
forEachOrdered: 暗元素順序執行循環操作。
四.常用場景和方法舉例
1.迭代
forEach()方法:void forEach(Consumer< ? super T> action);
peek()方法:Stream peek(Consumer< ? super T> action);
List<String> list=... // 傳統for循環 for (String s : list) { System.out.println(s); } // 使用forEach(結束操作),對集合的修改不會影響原集合 list.stream().forEach(x -> { System.out.println(x); }); // 使用peek(中間操作),對集合的修改也會體現在原集合中 list = list.stream().peek(x -> { System.out.println(x); }).collect(Collectors.toList());
2.轉換
map()方法:Stream map(Function< ? super T, ? extends R> mapper);
public class Person { private Integer id; private String name; private String sex; private Integer age; //提供get,set,和滿參構造函數 } public class TestMap { public static void main(String[] args) { List<Person> persionList = new ArrayList<Person>(); persionList.add(new Person(1,"張三","男",38)); persionList.add(new Person(2,"小小","女",2)); persionList.add(new Person(3,"李四","男",65)); persionList.add(new Person(4,"王五","女",20)); persionList.add(new Person(5,"趙六","男",38)); persionList.add(new Person(6,"大大","男",65)); //1、只取出該集合中所有姓名組成一個新集合 List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList()); //未去重 List<String> nameList=persionList.stream().map(Person::getName).distinct().collect(Collectors.toList()); //去重 System.out.println(nameList.toString()); //2、只取出該集合中所有id組成一個新集合 List<Integer> idList=persionList.stream().mapToInt(Person::getId).boxed().collect(Collectors.toList()); System.out.println(idList.toString()); //3、list轉map,key值為id,value為Person對象 Map<Integer, Person> personmap = persionList.stream().collect(Collectors.toMap(Person::getId, person -> person)); System.out.println(personmap.toString()); //4、list轉map,key值為id,value為name Map<Integer, String> namemap = persionList.stream().collect(Collectors.toMap(Person::getId, Person::getName)); System.out.println(namemap.toString()); //5、進行map集合存放,key為age值 value為Person對象 它會把相同age的對象放到一個集合中 Map<Integer, List<Person>> ageMap = persionList.stream().collect(Collectors.groupingBy(Person::getAge)); System.out.println(ageMap.toString()); //6、獲取最小年齡 Integer ageMin = persionList.stream().mapToInt(Person::getAge).min().getAsInt(); System.out.println("最小年齡為: "+ageMin); //7、獲取最大年齡 Integer ageMax = persionList.stream().mapToInt(Person::getAge).max().getAsInt(); System.out.println("最大年齡為: "+ageMax); //8、集合年齡屬性求和 Integer ageAmount = persionList.stream().mapToInt(Person::getAge).sum(); System.out.println("年齡總和為: "+ageAmount); } }
3.過濾
filter()方法:Stream filter(Predicate< ? super T> predicate);
public class TestFilter { public static void main(String[] args) { List<Person> persionList = new ArrayList<Person>(); persionList.add(new Person(1, "張三", "男", 8)); persionList.add(new Person(2, "小小", "女", 2)); persionList.add(new Person(3, "李四", "男", 25)); persionList.add(new Person(4, "王五", "女", 8)); persionList.add(new Person(5, "趙六", "女", 25)); persionList.add(new Person(6, "大大", "男", 65)); //1、查找年齡大於20歲的人數 long age=persionList.stream().filter(p->p.getAge()>20).count(); System.out.println(age); //2、查找年齡大於20歲,性別為男的人數 List<Person> ageList=persionList.stream().filter(p->p.getAge()>20).filter(p->"男".equals(p.getSex())).collect(Collectors.toList()); System.out.println(ageList.size()); //3、查找年齡大於20歲的男性 或 年齡大於18歲的女性人數 List<Person> ageList=persionList.stream().filter(p -> (p.getAge()>20 && "男".equals(p.getSex())) || (p.getAge()>18 && "女".equals(p.getSex()))).collect(Collectors.toList()); System.out.println(ageList.size()); //4、過濾掉 姓名、性別、年齡 均相同的重復項 List<Person> ageList=persionList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(p -> p.getName() + ";" + p.getSex() + ";" + p.getAge()))), ArrayList::new)); System.out.printIn(ageList.size()); } }
4.排序
sorted() 排序方法:
public class Test { public static void main(String[] args) { List<Person> persionList = new ArrayList<Person>(); persionList.add(new Person(1, "張三", "男", 8)); persionList.add(new Person(2, "小小", "女", 2)); persionList.add(new Person(3, "李四", "男", 25)); persionList.add(new Person(4, "王五", "女", 8)); persionList.add(new Person(5, "趙六", "女", 25)); persionList.add(new Person(6, "大大", "男", 65)); //根據年齡升序 persionList = persionList.stream().sorted(Comparator.comparing(Person::getAge)).collect(Collectors.toList()); persionList = persionList.stream().sorted(Comparator.comparingInt(x -> x.getAge())).collect(Collectors.toList()); persionList = persionList.stream().sorted((a, b) -> a.getAge().compareTo(b.getAge())).collect(Collectors.toList()); //根據年齡降序 persionList = persionList.stream().sorted(Comparator.comparing(Person::getAge).reversed()).collect(Collectors.toList()); persionList = persionList.stream().sorted((a, b) -> b.getAge().compareTo(a.getAge())).collect(Collectors.toList()); //根據年齡降序,年齡相同的再根據id升序 persionList = persionList.stream().sorted(Comparator.comparing(Person::getAge).reversed().thenComparing(Person::getId)).collect(Collectors.toList()); } }