Java 8 新特性 —— Stream API

強大的Stream API

所在包爲: java.util.stream.*

Stream 是 java 8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常複雜的 查找、過濾和映射數據 等操作。使用 Stream api 的操作,就類似使用SQL 執行的數據庫查詢,。也可以使用 Stream API 來並行執行操作。

簡而言之,Stream API 提供了一種高效且易於使用的處理數據的方式

1. 流(Stream) 到底是什麼?

​ 流是數據渠道,用於操作數據源(集合、數組等)所生成的元素序列。、

​ ”集合講的是數據,流講的是計算“

note: ① Stream 不會存儲元素

​ ② Stream 不會改變源對象。相反,他們會返回一個持有結果的新的 Stream。

​ ③ Stream 操作時延遲執行的。這意味着他們會等到需要結果的時候才執行。

2. Stream 操作三個步驟

  1. 創建 Stream
  2. 中間操作
  3. 終止操作(終端操作)

2.1 創建 Stream 的方式

// 1. 可以通過 Collection 系列集合提供的 stream() 或 parallelStream()
// stream() 獲取串行流;parallelStream() 獲取並行流;
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();

// 2. 通過 Arrays 中的靜態方法 stream() 獲取數據流
Employee [] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);

// 3. 通過 Stream 類中的靜態方法 of()
Stream<String> stream3 = Stream.of("a", "b", "c");

// 4. 創建無限流
// 迭代
//        函數式接口
//        Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//
// @FunctionalInterface
// public interface UnaryOperator<T> extends Function<T, T> {
//
//    static <T> UnaryOperator<T> identity() {
//        return t -> t;
//    }
// }
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x+2);

stream4.limit(10).forEach(System.out::println); // 中間操作+終止操作

// 生成
Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);

2.2 中間操作

  1. /*
        篩選和切片
        filter ——接受 Lambda,從流中排除某些元素
        limit —— 截斷流,使其元素不超過給定數量
        skip(n) —— 跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit() 互補;
        注意該方法所執行的位置, 會在其之前的其他篩選方法之後的結果上進行跳過元素
        distinct —— 篩選,通過流所生成元素的 hashCode() 和 equals() 去重複元素
        (故使用該方法篩選, 需要先重寫hashCode, equals )
    */
    Stream<String> stream = list.stream()	
        						.filter((e) -> {
                                    return e.getId() > 1;
                                })
        						.skip(2)
                                .limit(10)
                                .distinct();
    
    /*
        映射
        map —— 接受 lambda 表達式,將元素轉換成其他i形式或提取信息。接受一個函數作爲參數,該參數會被應用到每一個元素上,並將其映射成一個新的元素。
        flatMap —— 接受一個函數作爲參數,將流中的每個值都換成另外一個流,然後把所有流連接成一個流
    */
    public class TestStream02 {
        @Test
        public void test(){
            List<String> list = Arrays.asList("a", "b", "CC", "dd");
    
            Stream<Stream<Character>> streamStream = list.stream()
                .map(TestStream02::filterCharacter);
    
            streamStream.forEach((x) -> {
                x.forEach(System.out::println);
            });		// 終止操作,打印輸出
    
            System.out.println("=======================================");
            System.out.println("以上代碼效果與以下代碼相同");
            System.out.println("=======================================");
            list.stream()
                .flatMap(TestStream02::filterCharacter)
                .forEach(System.out::println);
        }
        public static Stream<Character> filterCharacter(String str){
            // 省略具體實現
        }
    }
    
    /*
        排序
        sorted() —— 自然排序 (Comparable)
        sorted(Comparator com) —— 定製排序(Comparator), 自己實現 Comparator 函數式接口
     */
    List<String> list = Arrays.asList("a", "b", "CC", "dd");
    
    list.stream().sorted().forEach(System.out::println);
    
    System.out.println("====================================");
    
    employees.stream().sorted((e1, e2) -> {
        if(e1.getId() == e2.getId()) {
            return e1.getName().compareTo(e2.getName());
        } else {
            return e1.getId().compareTo(e2.getId());
        }
    }).forEach(System.out::println);
     
    
注:

中間操作 不會執行任何操作;直到發生 終止操作 才一次性執行全部內容,即"惰性求值"

2.3 終止操作(終端操作)

/*
    1. 查找與匹配
    allMatch —— 檢查是否匹配所有元素
    anyMatch —— 檢查是否至少匹配一個元素
    noneMatch —— 檢查是否沒有匹配所有元素
    findFirst —— 返回第一個元素
    findAny —— 返回當前流中的任意元素
    count —— 返回流中元素的總個數
    max —— 返回流中最大值
    min —— 返回流中最小值
 */
// allMatch、anyMatch、noneMatch 實現 Predicate 函數式接口做匹配檢查
boolean b1 = employees.stream()
                .allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));

List<String> list = Arrays.asList("a", "b", "CC", "dd");
list.stream().findFirst();

list.stream().findAny();
list.stream().count();
Optional<String> op = list.stream().max(String::compareTo);
Optional<String> op = list.stream().min(String::compareTo);


/*
    2. 規約
    reduce(T identity, BinaryOperator) / reduce(BinaryOperator) —— 可以將流中元素反覆結合起來,得到一個值
 */
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

// reduce(T identity, BinaryOperator)
// 0 代入 x, list的流一個一個元素代入y, 將計算結果重新代入 x, 將下一個元素代入 y
Integer sum = list.stream().reduce(0, (x, y) -> x+y);

System.out.println("==================================");

Optional<Integer> op = employees.stream().map(Employee::getId).reduce(Integer::sum);
System.out.println("op:" + op.get());
/*
    3. 收集
    collect —— 將流轉換爲其他形式。接受一個Collector 接口的實現,用於給 Stream 中元素做彙總的方法
 */
public class TestStream04 {

    List<Employee> employees = Arrays.asList(
            new Employee(1, "atom", Employee.Status.BUSY),
            new Employee(2, "jashon", Employee.Status.FREE),
            new Employee(3, "Linus", Employee.Status.VOCATION),
            new Employee(4, "henry", Employee.Status.FREE),
            new Employee(4, "cenry", Employee.Status.VOCATION),
            new Employee(4, "zenry", Employee.Status.BUSY),
            new Employee(3, "Jack", Employee.Status.BUSY)
    );

    @Test
    public void test8() {
        String str = employees.stream().map(Employee::getName)
                .collect(Collectors.joining(",", "-> ", " <-"));
//                .collect(Collectors.joining(","));
        System.out.println(str);
    }


    @Test
    public void test7() {
        // 此方法可獲得 test3 中所計算的值
        IntSummaryStatistics iss = employees.stream().collect(Collectors.summarizingInt(Employee::getId));

        System.out.println(iss.getAverage());
        System.out.println(iss.getCount());
        System.out.println(iss.getCount());
        System.out.println(iss.getMax());
        System.out.println(iss.getMin());
    }

    @Test
    public void test6() {
        Map<Boolean, List<Employee>> map = employees.stream()
                .collect(Collectors.partitioningBy((e) -> e.getId() > 3));
        System.out.println(map);
    }

    // 多級分組
    @Test
    public void test5() {

        Map<Employee.Status, Map<String, List<Employee>>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if(((Employee) e).getId() < 3) {
                        return "靠前";
                    } else {
                        return "靠後";
                    }
                })));

        System.out.println(map);

    }

    // 分組
    @Test
    public void test4() {
        Map<Employee.Status, List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));

        System.out.println(map);
    }


    // 計算
    @Test
    public void test3() {
        // 總數
        long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println("total:" + count);

        System.out.println("=======================");

        // 平均值
        Double avg = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getId));
        System.out.println("avg:" + avg);

        System.out.println("=======================");

        // 總和
        Integer sum = employees.stream()
                .collect(Collectors.summingInt(Employee::getId));
        System.out.println("sum:" + sum);

        System.out.println("=======================");

        // 最大值的對象
        Optional<Employee> max = employees.stream()
                .collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getId(), e2.getId())));
        System.out.println("最大值: " + max.get());

        System.out.println("=======================");

        // 最小值
        Optional<Integer> min = employees.stream()
                .map(Employee::getId)
                .collect(Collectors.minBy(Integer::compare));
        System.out.println("最小值: " + min.get());
    }

    // 收集獲得集合
    @Test
    public void test2() {
        List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList());
        list.forEach(System.out::println);

        System.out.println("=======================");

        Set<String> set = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
        set.forEach(System.out::println);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章