java8新特性之強大的Stream API

Stream API

Stream是Java8中處理集合的關鍵抽象概念,它能夠指定你但願對集合進行的操做,能夠執行很是複雜的查找、過濾和映射數據等操做。
使用Stream API 對集合數據進行操做,就相似於使用 SQL 執行的數 據庫查詢。
也可使用Stream API來並行執行操做。
簡而言之,Stream API 提供了一種高效且易於使用的處理數據的方式。

流(Stream) 究竟是什麼呢?

Stream流是數據渠道,用於操做數據源(集合、數組等)所生成的元素序列,如下三點注意。
  1. Stream 本身不會存儲元素。
  2. Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。
  3. Stream 操做是延遲執行的。這意味着他們會等到須要結果的時候才執行。
Stream流操做的三大步
  1. 建立Stream流 //一個數據源 集合/數組/Stream靜態方法 獲取一個Stream流
  2. 中間操做 //對數據源的數據進行處理,過濾,篩選等等
  3. 終止操做 //執行中間操做鏈,產生結果

建立Stream流

1.集合建立Stream流
/****
     * java8中的Collection接口方法
     * stream() 順序流
     * parallelStream()  並行流(後面再說這個)
     */
    @Test
    public void test01() {
        //聲明一個list
        List<String> list = new ArrayList<String>();
        //  default Stream<E> stream() 順序流
        //  default Stream<E> parallelStream()  並行流
        //  建立一個順序流
        Stream stream1 = list.stream();
        //  建立一個並行流
        Stream stream2 = list.parallelStream();
    }
2.數組建立Stream流
/****
     * 數組建立Stream流
     * Java8 中的 Arrays 的靜態方法 stream() 能夠獲取數組流
     */
    @Test
    public void test02() {
        //   Java8 中的 Arrays 的靜態方法 stream() 能夠獲取數組流
        //    public static <T> Stream<T> 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<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        Stream stream1 = Stream.iterate(0, (x) -> x + 1);

        //args 一個供給型接口
        // 生成   public static<T> Stream<T> generate(Supplier<T> s) :
        Stream stream2 = Stream.generate(() -> new Random().nextInt(100));

    }

Stream流中間操做

多箇中間操做能夠鏈接起來造成一個流水線,除非流水線上觸發終止操做,不然中間操做不會執行任何的處理,而在終止操做時一次性所有處理,稱爲「惰性求值」。看一下一些經常使用的api:java

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<Integer> 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<Integer> 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<Integer> 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<Integer> 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<Integer> 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<String> 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、booleansql

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<Integer> 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<Integer> 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<Integer> 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<Integer> 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<Integer> 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<T> 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<T> 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<Integer> 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<Integer> 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<Integer> 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<Integer> 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<Employee> 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<Employee> 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<Employee> 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<Employee> 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<Employee> 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<Employee> 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<Integer> 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<U> op)
     * 從一個做爲累加器的初始值開始,利用BinaryOperator與流中元素逐個結合,從而歸約成單個值
     * 接收二元計算接口
     */
    @Test
    public void test20() {
        List<Employee> 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<Employee> 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<T,A,R> downstream,Function<R,RR> finisher)
     *  轉換函數返回的類型
     *  包裹另外一個收集器,對其結果轉換函數
     */
    @Test
    public void test21() {
        List<Employee> 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<Employee> 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<Employee> 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<Employee> 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<Employee> 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<Employee> 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歡迎來留言啊!!!api

相關文章
相關標籤/搜索