Stream的一些常用操作

    由於最近換了工作,項目中是使用jdk1.8,所以有必要學習一些jdk1.8騷操作,此文章不斷更新。

    如何理解Stream?在我看來,Stream 不是集合元素,它不是數據結構並不保存數據,它是有關算法和計算的,它更像一個高級版本的 Iterator。簡單來說,它的作用就是通過一系列操作將數據源(集合、數組)轉化爲想要的結果。

Stream有三點非常重要的特性:

  1. Stream 是不會存儲元素的。
  2. Stream 不會改變原對象,相反,他們會返回一個持有結果的新Stream。
  3. Stream 操作是延遲執行的。意味着它們會等到需要結果的時候才執行。

Stream生成

//Collection系的 stream() 和 parallelStream()
List<String> list = new ArrayList<> ();
Stream<String> stream = list.stream();
Stream<String> stringStream = list.parallelStream();

 //通過Arrays.stram()
 Stream<String> stream1 = Arrays.stream(new String[10]);

//通過Stream.of()
Stream<Integer> stream2 = Stream.of(1, 2, 3,4,5,6,7,8,9,10);

//通過Stream.iterate()生成無限流
Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
iterate.limit(10).forEach(System.out::println);

//通過Stream.generate()
Stream<Double> generate = Stream.generate(() -> Math.random());

Stream中間操作

stream2.map(s -> s + 1) //映射
                .flatMap(s -> Stream.of(s)) //和map差不多,但返回類型爲Stream,類似list.add()和list.addAll()的區別
                .filter(s -> s <=5 ) //過濾
                .limit(5) //限制
                .skip(1) //跳過
                .distinct() //去重
                .sorted() //自然排序
                .sorted(Integer::compareTo).forEach (System.out::println); //自定義排序*/

Stream的終止操作  (不能對同一個流一遍進行運行操作,一遍終止操作)

常用的終止API如下: 

 System.out.println (stream2.allMatch((x) -> x == 10));  // 檢查是否匹配所有元素 boolean
 System.out.println(stream2.anyMatch(((x) -> x>5))); // 檢查是否至少匹配一個元素
 System.out.println(stream2.noneMatch((x) -> x>500)); //檢查是否沒有匹配所有元素
 System.out.println (stream2.findFirst()); // 返回第一個元素Optional[1]
 System.out.println (stream2.findAny()); // 返回當前流中的任意一個元素;
 System.out.println (stream2.count()); // 返回流中元素的總個數);
 Optional<Integer> max = stream2.max(Integer::compareTo); // 返回流中最大值
 System.out.println("max "+max.get());
 Optional<Integer> min = stream2.min(Integer::compareTo);//返回流中最小值
 System.out.println("min "+min.get());

  reduce (歸約):將流中元素反覆結合起來得到一個值 

 Integer reduce = stream2.map(s -> (s + 1)).reduce(0, (integer1, integer2) -> integer1+integer2); 
//歸約:0爲第一個參數x的默認值,x是計算後的返回值,y爲每一項的值。
 System.out.println(reduce);
 Optional<Integer> reduce1 = stream2.map(s -> (s + 1)).reduce((x, y) -> x + y);
// x是計算後的返回值,默認爲第一項的值,y爲其後每一項的值。 
 System.out.println(reduce1.get ());

collect(收集):將流轉換爲其他形式。需要Collectors類的一些方法

//collect(收集):將流轉換爲其他形式。需要Collectors類的一些方法。
Set<Integer> collect = stream2.collect(Collectors.toSet());
List<Integer> collect2 = stream2.collect(Collectors.toList());
HashSet<Integer> collect1 = stream2.collect(Collectors.toCollection(HashSet::new));
//分組 {group=[1, 2, 3, 4...]}
Map<String, List<Integer>> collect3 = stream2.collect(Collectors.groupingBy((x) -> "group"));//將返回值相同的進行分組
//分區 {false=[1, 2, 3, 4], true=[5, 6, 7, 8, 9, 10, 10]}
Map<Boolean, List<Integer>> collect5 = stream2.collect(Collectors.partitioningBy((x) -> x >= 5));
//彙總  最大值、最小值、平均值、個數
DoubleSummaryStatistics collect6 = stream2.collect(Collectors.summarizingDouble((x) -> x));
System.out.println(collect6.getMax());
System.out.println(collect6.getCount());

摘自: https://mp.weixin.qq.com/s/5UUD7N4Uxspnzcine_2AnA

工作常用示例

package JDK8常用特性;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Heian
 * @time 19/04/01 14:15
 * 用途:
 */
public class Demo1 {

    class Student{
        private int id;
        private String name;
        private int age;
        public Student(int id,String name,int age){
            this.id = id;
            this.name = name;
            this.age = age;
        }
        public int getId() {
            return id;
        }
        public String getName() {
            return name;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    public static void main(String[] args) {
        Demo1 demo1 = new Demo1 ();
        List<Student> list = new ArrayList<> ();
        list.add (demo1.new Student (1,"張三",18));
        list.add (demo1.new Student (2,"李四",20));
        list.add (demo1.new Student (3,"王二",22));
        list.add (demo1.new Student (4,"小明",19));
        list.add (demo1.new Student (5,"小紅",17));
        list.add (null);
        //常用操作一:防空處理
        //Optional.ofNullable (list).orElse (Collections.emptyList ()).forEach (System.out::println);  會存在null
        list.stream ().filter (Objects::nonNull).forEach (student -> System.out.println (student));
        //常用操作二:集合變形  業務代碼最爲常見(假設我要取得某個集合中某個屬性作爲單獨的一個集合)
        System.out.println ("=======================集合變形分割線===================");
        List<String> nameList = list.stream ().filter (Objects::nonNull).map (Student::getName).collect(Collectors.toList());
        nameList.forEach (System.out::println);//集合轉化流--->filter過濾--->map對集合做業務操作(返回的仍然是Stream<R>)--->流轉化爲集合
        //limit 就像mysql的limit num 關鍵字  這裏是查出前3條
        List<String> nameList2 = list.stream ().filter (Objects::nonNull).map (Student::getName).limit (3).collect(Collectors.toList());
        nameList2.forEach (s -> System.out.println ("limit" + s));
        //加上skip 類似於mysql分頁 比如查看第1 到 10 條記錄 select * from emp limit 0,9     這裏也類似:這就是第2到第4條   也可以用於分頁
        List<String> nameList3 = list.stream ().filter (Objects::nonNull).map (Student::getName).skip (1).limit (3).collect(Collectors.toList());
        nameList3.forEach (s -> System.out.println ("skip  limit" + s));
        List<Integer> list2 = Arrays.asList(1,2,3);
        //不改變原有元素
        list2.forEach(i -> i = i*2);
        list2.forEach(integer -> System.out.println ("不改變原有元素"+integer));
        //改變對象
        list2.stream().map(i -> i * 2).forEach(integer -> System.out.println ("改變原有元素"+integer));
        //常用操作三:list轉map
        System.out.println ("=======================list轉map分割線===================");
        Map<Integer,Student> map = list.stream ().filter (Objects::nonNull).collect (Collectors.toMap (Student::getId,student -> student));
        for (Map.Entry<Integer, Demo1.Student> entrySet: map.entrySet ()){
            System.out.println (entrySet.getKey () +":"+ entrySet.getValue ());
        }
        System.out.println ("=======================排序後分割線===================");
        //常用操作四:集合排序
        //方法1:利用Comparable 接口實現排序 String和Integer都是實現了此接口,需要覆寫其
        List<Student> notNullList = list.stream ().filter (Objects::nonNull).collect (Collectors.toList ());
        Collections.sort (notNullList,(o1, o2) -> {
            return Integer.compare (o1.age,o2.age);
        });
        //利用Comparator 接口實現排序
        Collections.sort (notNullList,Comparator.comparing (o -> o.age));
        notNullList.forEach (student -> System.out.println (student));

        //當然覺得性能差 可以用並行方式輸出,但結果不一定是順序執行 1234...9
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        numbers.parallelStream().forEach(System.out::println);
        numbers.parallelStream ().forEachOrdered (System.out::println);//順序執行
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章