在介紹Stream以前,咱們先來講說Java8中的另外一個新特性:Lambda,直接上代碼吧java
在Java8以前,list自定義排序會使用匿名內部類,實現本身的排序邏輯程序員
stuList.sort(new Comparator<Student>() { @Override public int compare(Student stu1, Student stu2) { return stu1.getAge().compareTo(stu2.getAge()); } });
下面看一下Lambda表達式的寫法:web
stuList.sort((s1,s2) -> s1.getAge().compareTo(s2.getAge()));
能夠看到,從代碼量和整潔程度來講,Lambda都顯得都簡潔編程
Lambda表達式是表示可傳遞匿名方法的一種簡潔方式,Lambda表達式沒有名稱,可是有參數列表、函數主體、返回類型,還可能有一個能夠拋出的異常列表數組
|<----------參數--------->|<-箭頭->|<----------------主體---------------| (Student stu1,Student stu2) -> stu1.getAge().compareTo(stu2.getAge())
從上面Lambda的組成能夠看出來,Lambda有兩種簡單的語法:微信
方法引用是Java8中引入的新特性,它提供了一種引用方法而不執行方法的方式,可讓咱們重複使用現用方法的定義,作爲某些Lambda表達式的另外一種更簡潔的寫法併發
好比:dom
stuList.sort((s1,s2) -> s1.getAge().compareTo(s2.getAge()));
可使用方法引用簡寫爲:ide
Comparator comparator = Comparator.comparing(Student::getAge);
當你須要方法引用時,目標引用放在分隔符::前,方法的名稱放在分隔符::後。好比,上面的Student::getAge,就是引用了Student中定義的getAge方法。方法名稱後不須要加括號,由於咱們並無實際調用它。方法引用提升了代碼的可讀性,也使邏輯更加清晰svg
好了,Lambda就簡單的介紹到這裏,更多Lambda的詳細用法能夠直接百度本身學習一下
Java8中添加一個新的抽象概念叫作Stream,它可使用相似SQL語句的形式來處理Java集合的運算。
Stream提供了一種「鏈式」編程,能把一系列的操做像鏈條同樣串連起來,這種風格的處理方式把集合看做是一種流,流在管道中傳輸,每一步操做均可以看做是管道中的一個節點,全部節點處理完成造成最終的結果
舉個形象的例子,Stream的操做相似於流水線生產,整個產品線從頭至尾造成一條鏈路,每一個環節就是一個處理節點,最終全部節點處理完成就造成了最終的產品
Stream API簡化了集合的各類操做,提升了程序員的生產力,讓程序員能寫出高效率、乾淨、整潔的代碼
public void create() throws FileNotFoundException { Stream<String> stringStream = Stream.of("a","b","c"); Stream<String> stringStream1 = Stream.of("d","e","f"); //經過concat將兩個Stream鏈接成一個Stream Stream<String> stringStream2 = Stream.concat(stringStream,stringStream1); stringStream2.forEach(str -> System.out.println(str)); //經過迭代器建立Stream Stream<Integer> integerStream = Stream.iterate(0,(x) -> (x + 1)).limit(10); //generate建立Stream Stream<Double> doubleStream = Stream.generate(Math::random).limit(5); //經過集合建立stream List<String> list = Lists.newArrayList("a","b","c"); Stream<String> listStream = list.stream(); Stream<String> parallelStream = list.parallelStream();//併發流 //數組轉換成Stream String[] stringArr = new String[]{"a","b","c"}; Stream<String> arrStream = Arrays.stream(stringArr); //文件流轉換成Stream BufferedReader reader = new BufferedReader(new FileReader("D:\\test.txt")); Stream<String> fileStream = reader.lines(); }
Stream中的操做分爲兩類
|<------Stream------>| |<-------中間操做--------->|<--終止操做-->| +--------------------+ +------+ +------+ +---+ +-------+ | stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect| +--------------------+ +------+ +------+ +---+ +-------+
中間操做就是操做以後,Stream仍然是一個Stream,可使用其餘的中間操做繼續對結果進行操做
public void mapTest(){ List<Integer> list = Lists.newArrayList(1,2,3,4,5); //map就是傳入一個函數,將list中的全部元素都套用這個函數 Stream<Integer> stream = list.stream().map(x -> x * x); stream.forEach(x -> System.out.println(x)); List<String> flapList = Lists.newArrayList("a#b#c","1#2#3"); //flatMap就是傳入一個函數,將每一個元素轉換成另一個流,再將全部的流鏈接成一個流 Stream<String> flagStream = flapList.stream().flatMap(x -> { String[] strArr = x.split("#"); Stream<String> tmpStream = Arrays.stream(strArr); return tmpStream; }); flagStream.forEach(x -> System.out.println(x)); //a b c 1 2 3 }
public void filterTest(){ List<Integer> list = Lists.newArrayList(1,2,3,4,5); //filter就是傳入過濾的規則,對stream中的元素進行過濾 list.stream().filter(x -> x > 3).forEach(x -> System.out.println(x)); }
public void limitTest(){ List<String> list = Lists.newArrayList("a","b","c","x","y","z"); //limit傳入一個數字,取stream中前面幾個元素 list.stream().limit(3).forEach(x -> System.out.println(x)); }
public void skipTest(){ List<Integer> list = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); //跳過前三個元素 list.stream().skip(3); //skip配合limit可實現分頁,好比每頁5筆記錄 list.stream().skip(5 * 0).limit(5);//第一頁 list.stream().skip(5 * 1).limit(5);//第二頁 list.stream().skip(5 * 2).limit(5);//第三頁 }
public void distinctTest(){ List<String> list = Lists.newArrayList("a","b","c","a","a","c","c","e","f"); //去掉重複元素 list.stream().distinct(); }
public void sortedTest(){ //sorted是對元素進行天然排序,當遇到對象排序時,能夠自定義經過對象的屬性來排序 List<String> list = Lists.newArrayList("a","b","c","a","a","c","c","e","f"); list.stream().sorted(); List<Integer> intList = Lists.newArrayList(1,5,5,3,9,4,4,7,6); intList.stream().sorted(); }
public void peekTest(){ List<String> list = Lists.newArrayList("a","b","c","a","a","c","c","e","f"); //peek傳入一個Consumer,沒有返回值,不改變Stream中原來的元素,注意對比map list.stream().peek(x -> x = x + "666"); }
終止操做符就是用來對數據進行收集或者消費的,數據到了終止操做這裏就不會向下流動了,終止操做符只能使用一次
public void matchTest(){ List<Integer> list = Lists.newArrayList(12,14,3,24,5,23,77); list.stream().allMatch(x -> x > 10); //全部元素知足條件才返回true list.stream().noneMatch( x -> x > 100);//全部元素不知足條件才返回true list.stream().anyMatch(x -> x > 50);//只有一個元素知足就返回true }
public void findTest(){ List<Integer> list = Lists.newArrayList(12,14,3,24,5,23,77); list.stream().findFirst().get();//返回Stream中第一個元素 list.stream().findAny().get();//返回Steam中任意元素 }
將序列的內容從新組織到新的容器中,好比 List 或者 Map
public void collectTest(){ Student stu1 = new Student("stu1",11); Student stu2 = new Student("stu2",12); Student stu3 = new Student("stu3",13); Student stu4 = new Student("stu4",14); Student stu5 = new Student("stu5",15); List<Student> list = Lists.newArrayList(stu1,stu2,stu3,stu4,stu5); //將list中全部學生的姓名收集起來,放到一個新list中 List<String> nameList = list.stream().map(Student::getName).collect(Collectors.toList()); nameList.forEach(System.out::println); }
Collectors
Collectors提供了不少種Collector的建立方式
public void CollectorsTest(){ Student stu1 = new Student("stu1",11); Student stu2 = new Student("stu2",12); Student stu3 = new Student("stu3",13); Student stu4 = new Student("stu4",14); Student stu5 = new Student("stu5",15); List<Student> list = Lists.newArrayList(stu1,stu2,stu3,stu4,stu5); //將全部學生的姓名收集到新的list中 List<String> nameList = list.stream().map(Student::getName).collect(Collectors.toList()); //一樣能夠收集到Set中 Set<String> nameSet = list.stream().map(Student::getName).collect(Collectors.toSet()); //將每一個學生的name,age轉換成Map,如有名稱相同的會形成key相同致使失敗 Map<String,Integer> map = list.stream().collect(Collectors.toMap(Student::getName,Student::getAge)); //字符串鏈接 String nameJoin = list.stream().map(Student::getName).collect(Collectors.joining(";","(",")")); //---聚合操做---- //count Long count = list.stream().collect(Collectors.counting()); // max Integer maxAge = list.stream().map(Student::getAge).collect(Collectors.maxBy(Integer::compare)).get(); // sum Integer sumAge = list.stream().collect(Collectors.summingInt(Student::getAge)); // avg Double avgAge = list.stream().collect(Collectors.averagingDouble(Student::getAge)); // 全部聚合操做的返回 DoubleSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingDouble(Student::getAge)); summaryStatistics.getSum(); summaryStatistics.getAverage(); summaryStatistics.getCount(); summaryStatistics.getMax(); summaryStatistics.getMin(); //group 按年齡分組 Map<Integer,List<Student>> ageGroup = list.stream().collect(Collectors.groupingBy(Student::getAge)); //分區,分紅兩部分,一部分大於12歲,一部分小於等於12歲 Map<Boolean,List<Student>> agePartition = list.stream().collect(Collectors.partitioningBy(x -> x.getAge() > 12)); //規約 Integer reducingAge = list.stream().map(Student::getAge).collect(Collectors.reducing(Integer::max)).get(); }
能夠看到Collectors提供了不少方便的收集方式,讓咱們很方便的處理集合的各類操做
public void countTest(){ List<Integer> list = Lists.newArrayList(12,14,3,24,5,23,77); Long count = list.stream().count(); }
public void maxAndminTest(){ List<Integer> list = Lists.newArrayList(12,14,3,24,5,23,77); Integer max = list.stream().max(Integer::compareTo).get(); Integer min = list.stream().min(Integer::compareTo).get(); }
public void reduceTest(){ List<Integer> list = Lists.newArrayList(12,14,3,24,5,23,77); Integer sum = list.stream().reduce(0,(x,y) -> x + y); }
適用用於並行流的狀況下進行迭代,能保證迭代的有序性
public void forEachOrderedTest(){ List<Integer> list = Lists.newArrayList(12,14,3,24,5,23,77); list.stream().parallel().forEachOrdered(System.out::println); }
public void toArrayTest(){ List<Integer> list = Lists.newArrayList(12,14,3,24,5,23,77); Object[] objects = list.stream().toArray(); for(Object obj : objects){ System.out.println(obj); } }
經過這些方法的介紹,相信你對Java8 Stream API有了必定的瞭解,熟練掌握這些方法能使你的代碼更加簡潔。對於Java8這種「鏈式」編程的風格究竟是否應該推薦使用也是見仁見智,網上不少人說Stream API若是寫的很長,確實能夠減小代碼,但這樣會致使邏輯不夠清晰,寫的人很爽,看的人難受。筆者所在技術團隊目前尚未大量使用Stream API,你們仍是習慣於用日常的語法來寫業務邏輯。
你所在的團隊會大量的用到Stream API來減小代碼量嗎?歡迎給我留言~
若是感受對你有些幫忙,請收藏好,你的關注和點贊是對我最大的鼓勵!
若是想跟我一塊兒學習,堅信技術改變世界,請微信搜索【Java天堂】關注我,我會按期分享本身的學習成果,第一時間推送給您
參考:
https://blog.csdn.net/y_k_y/article/details/84633001
https://www.jianshu.com/p/11c925cdba50