菜鳥的java8新特性探索

說明

更新時間:2020/5/29 11:11,更新了基本功能

關於java8新特性,很久之前就聽說過了,現在將java8新特性中的Stream api的使用記錄在這裏,以便日後查看,本文會持續更新,不斷地擴充

本文僅爲記錄學習軌跡,如有侵權,聯繫刪除

一、關於java8新特性

Java 8 (又稱爲 jdk 1.8) 是 Java 語言開發的一個主要版本。 Oracle 公司於 2014 年 3 月 18 日發佈 Java 8 ,它支持函數式編程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。

其中個人u覺得最重要的新特性Stream API,個人使用的也比較頻繁,雖然當時不知道這是java8的新特性,Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中。

二、Stream

Stream流使用流程:開始---->中間操作---->終止操作

開始包括流的創建,中間操作包括對創建的流進行篩選、聚合等操作,終止操作則將得到的結果轉爲某種形式輸出

/**
 * Java從8開始,不但引入了Lambda表達式,還引入了一個全新的流式API:Stream API。它位於java.util.stream包中。
 *
 * 劃重點:這個Stream不同於java.io的InputStream和OutputStream,它代表的是任意Java對象的序列。
 *
 * Stream API的基本用法就是:創建一個Stream,然後做若干次轉換,最後調用一個求值方法獲取真正計算的結果:
 *
 * 注意:把數組變成Stream使用Arrays.stream()方法。對於Collection(List、Set、Queue等),直接調用stream()方法就可以獲得Stream。
 */

stream的創建

主要分兩類,數組和集合(List、Map、Set)

//數組變成Stream使用Arrays.stream()方法
	int[] nums = {1,2,3,4,5,6,7,8,9,10};
	Arrays.stream(nums).forEach(n->{
	    //用forEach()遍歷數組無法獲取下標
	    System.out.println("n = "+n);
	});

//對於Collection(List、Set、Queue等),直接調用stream()方法就可以獲得Stream
    List<String> list = new ArrayList<>();
    list.add("灰太狼");
    list.add("喜羊羊");
    list.add("小灰灰");
    list.add("懶羊羊");
    list.stream().forEach(l->{
        System.out.println("index = "+list.indexOf(l)+"    value = "+l);
    });

Stream的中間操作

下面整理很多常用的一些中間操作,包括求和,過濾、平均值、排序等,具體如下
可能用到的兩個實體類

class User{
    private Integer id;
    private String name;
    private Date birthday;
    private Integer age;
    private String sex;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

    public User(Integer id, String name, Date birthday, Integer age, String sex) {
        this.id = id;
        this.name = name;
        this.birthday = birthday;
        this.age = age;
        this.sex = sex;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Date getBirthday() {
        return birthday;
    }
}


class Account {
    private Integer id;
    private String name;

    public Account() {
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public Account(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

(1)forEach()

    /**
     * Stream中間操作 1.forEach()
     * 循環每一個元素
     */
    public static void StreamForEcach(){
        /**
         * 數組
         */
        System.out.println("--------------------數組的forEach()--------------------");
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        Arrays.stream(nums).forEach(n->{
            //用forEach()遍歷數組無法獲取下標
            System.out.println("n = "+n);
        });


        /**
         * List
         */
        System.out.println("--------------------List的forEach()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("小灰灰");
        list.add("懶羊羊");
        list.stream().forEach(l->{
            System.out.println("index = "+list.indexOf(l)+"    value = "+l);
        });

        /**
         * map
         */
        System.out.println("-------------------Map的forEach()--------------------");
        Map<String,String> map = new HashMap<>();
        map.put("狼1","灰太狼");
        map.put("狼2","小灰灰");
        map.put("羊1","喜羊羊");
        map.put("羊2","懶羊羊");

        //map遍歷方式1
        System.out.println("map遍歷方式1:");
        map.keySet().forEach(key -> {
            System.out.println("key : "+key+"    value : "+map.get(key));
        });

        //map遍歷方式2
        System.out.println("map遍歷方式2:");
        map.entrySet().forEach(entry -> {
            System.out.println("key : " + entry.getKey() + "    value : " + entry.getValue());
        });

        //map遍歷方式3
        System.out.println("map遍歷方式3:");
        map.forEach((key,value)->{
            System.out.println("key : "+key+"    value : "+value);
        });

        /**
         * set
         */
        System.out.println("--------------------set的forEach()--------------------");
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        set.forEach(s->{
            System.out.println(s);
        });
    }

(2)filter()

    /**
     * Stream中間操作 2.filter()
     * 過濾篩選出符合某些條件的項,filter(條件 && 條件)
     */
    public static void StreamFilter(){
        /**
         * 數組
         */
        System.out.println("--------------------數組的filter()--------------------");
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        //篩選出除了10的所有偶數
        int[] newNums = Arrays.stream(nums).filter(n -> (n % 2 == 0 && n != 10)).toArray();
        Arrays.stream(newNums).forEach(System.out::println);

        /**
         * List
         */
        System.out.println("--------------------List的filter()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("小灰灰");
        list.add("懶羊羊");
        //篩選出以"羊"結尾的項
        List<String> newList = list.stream().filter(l -> l.endsWith("羊")).collect(Collectors.toList());
        newList.forEach(System.out::println);

        /**
         * map
         */
        System.out.println("--------------------Map的filter()--------------------");
        Map<String,String> map = new HashMap<>();
        map.put("狼1","灰太狼");
        map.put("狼2","小灰灰");
        map.put("羊1","喜羊羊");
        map.put("羊2","懶羊羊");
        //通過以狼結尾的項篩選出灰太狼
        Map<String, String> newMap = map.entrySet().stream().filter(m -> {
            if (m.getKey().startsWith("狼") && m.getValue().equals("灰太狼")) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));

        newMap.forEach((k,v)->{
            System.out.println("key = "+k+"     value = "+v);
        });

        /**
         * set
         */
        System.out.println("--------------------Set的filter()--------------------");
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        //篩選出偶數
        Set<Integer> newSet = set.stream().filter(s -> s % 2 == 0).collect(Collectors.toSet());
        newSet.forEach(System.out::println);

    }

(3)limit()

    /**
     * Stream中間操作 3.limit()
     * 它是用於限制流中元素的個數,即取前n個元素,返回新的流
     */
    public static void StreamLimit(){
        /**
         * 數組
         */
        System.out.println("--------------------數組的limit()--------------------");
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        //取出前10個數
        int[] newNums = Arrays.stream(nums).limit(5).toArray();
        Arrays.stream(newNums).forEach(System.out::println);

        /**
         * List
         */
        System.out.println("--------------------List的limit()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("小灰灰");
        list.add("懶羊羊");
        //取出前兩項
        List<String> newList = list.stream().limit(2).collect(Collectors.toList());
        newList.forEach(System.out::println);

        /**
         * map
         */
        System.out.println("--------------------Map的limit()--------------------");
        Map<String,String> map = new HashMap<>();
        map.put("狼1","灰太狼");
        map.put("狼2","小灰灰");
        map.put("羊1","喜羊羊");
        map.put("羊2","懶羊羊");
        //取出前兩項
        Map<String, String> newMap = map.entrySet().stream().limit(2).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));

        newMap.forEach((k,v)->{
            System.out.println("key = "+k+"     value = "+v);
        });

        /**
         * set
         */
        System.out.println("--------------------Set的limit()--------------------");
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        //取出前兩項
        Set<Integer> newSet = set.stream().limit(2).collect(Collectors.toSet());
        newSet.forEach(System.out::println);

    }

(4)skip()

    /**
     * Stream中間操作 4.skip()
     * 該方法與limit()方法互補
     * skip()方法用於跳過前面n個元素,然後再返回新的流
     */
    public static void StreamSkip(){

        /**
         * 方法skip(n)的參數n的四種情況:
         *
         * (1)當n<0時,拋IllegalArgumentException異常;
         *
         * (2)當n=0時,相當沒有跳過任何元素,原封不動、完璧歸趙;
         *
         * (3)當0<n<length時,跳過n個元素後,返回含有剩下的元素的流;
         *
         * (4)當n>=length時,跳過所有元素,返回空流。
         */


        /**
         * 數組
         */
        System.out.println("--------------------數組的skip()--------------------");
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        //跳過前5項返回其餘的項
        int[] newNums = Arrays.stream(nums).skip(5).toArray();
        Arrays.stream(newNums).forEach(System.out::println);

        /**
         * List
         */
        System.out.println("--------------------List的skip()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("小灰灰");
        list.add("懶羊羊");
        ////跳過前2項返回其餘的項
        List<String> newList = list.stream().skip(2).collect(Collectors.toList());
        newList.forEach(System.out::println);

        /**
         * map
         */
        System.out.println("--------------------Map的skip()--------------------");
        Map<String,String> map = new HashMap<>();
        map.put("狼1","灰太狼");
        map.put("狼2","小灰灰");
        map.put("羊1","喜羊羊");
        map.put("羊2","懶羊羊");
        //跳過前2項返回其餘的項
        Map<String, String> newMap = map.entrySet().stream().skip(2).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));

        newMap.forEach((k,v)->{
            System.out.println("key = "+k+"     value = "+v);
        });

        /**
         * set
         */
        System.out.println("--------------------Set的skip()--------------------");
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        //跳過前2項返回其餘的項
        Set<Integer> newSet = set.stream().skip(2).collect(Collectors.toSet());
        newSet.forEach(System.out::println);
    }

(5)distinct()

    /**
     * Stream中間操作 5.distinct()
     * 去除重複項
     */
    public static void StreamDistinct(){
        /**
         * 數組
         */
        System.out.println("--------------------數組的distinct()--------------------");
        int[] nums = {1,2,3,1,2,34,4,5,5,8,4};
        //去除重複項
        int[] newNums = Arrays.stream(nums).distinct().toArray();
        Arrays.stream(newNums).forEach(System.out::println);

        /**
         * List
         */
        System.out.println("--------------------List的distinct()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("喜羊羊");
        list.add("懶羊羊");
        //去除重複項
        List<String> newList = list.stream().distinct().collect(Collectors.toList());
        newList.forEach(System.out::println);

        /**
         * map和set因爲不可重複性所以沒必要用到distinct()
         */

    }

(6)map()

    /**
     * Stream中間操作 6.map()
     * 可以將對象轉換爲其他對象
     * Stream.map()是Stream最常用的一個轉換方法,它把一個Stream轉換爲另一個Stream
     * 所謂map操作,就是把一種操作運算,映射到一個序列的每一個元素上。
     * 例如,對x計算它的平方,可以使用函數f(x) = x * x。我們把這個函數映射到一個序列1,2,3,4,5上,就得到了另一個序列1,4,9,16,25:
     */
    public static void StreamMap(){
        //將數組先轉爲Stream,再平方後再轉爲數組
        int[] nums = {1, 2, 3, 4, 5};
        int[] result1 = Arrays.stream(nums)
                .map(n -> n * n)
                .toArray();

        //將Strings列表轉換爲大寫
        List<String> list1 = Arrays.asList("a","b","c","d","e");
        List<String> newList1 = list1.stream().map(String::toUpperCase).collect(Collectors.toList());
        newList1.forEach(System.out::println);


        //對象列表 - >字符串列表
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
                );
        List<String> newUsers = users.stream().map(u -> u.getName()).collect(Collectors.toList());
        newUsers.forEach(System.out::println);


        //對象列表 - >其他對象列表(User  ->  Account)
        List<Account> accounts = users.stream().map(u -> {
            Account account = new Account();
            account.setId(u.getId());
            account.setName(u.getName());
            return account;
        }).collect(Collectors.toList());
        accounts.forEach(System.out::println);


    }

(7)sorted()

    /**
     * Stream中間操作 7.sorted()
     * 排序
     */
    public static void StreamSorted(){
        //將數組先轉爲Stream,再平方後再轉爲數組
        int[] nums = {11, 2, 32, 14, 5};
        int[] newNums = Arrays.stream(nums).sorted().toArray();
        Arrays.stream(newNums).forEach(System.out::println);



        //按對象的年齡排序
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
        );
        List<User> newUsers = users.stream().sorted((p1, p2) -> {
            return p1.getAge().compareTo(p2.getAge());
        }).collect(Collectors.toList());
        newUsers.forEach(System.out::println);


    }

除此之外還有其他的中間操作,以後遇到接着補充…

最終操作

最終操作將結果轉換成某種形式輸出

(1)allMatch()

    /**
     * Stream終止操作 1.allMatch()
     * 檢查是否匹配所有元素
     */
    public static void StreamAllMatch(){
        //判斷數組的元素是否都是在0-20之間
        int[] nums = {11, 2, 32, 14, 5};
        boolean isBetweenZeroTwenty = Arrays.stream(nums).allMatch(n -> (n >= 0) && (n <= 20));
        System.out.println("數組的元素是否都是在0-20之間:"+isBetweenZeroTwenty);


        //判斷user列表的元素的年紀是否都是大於等於18歲
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
        );
        boolean isAdult  = users.stream().allMatch(u -> u.getAge() >= 18);
        System.out.println("user列表的元素的年紀是否都是大於等於18歲:"+isAdult);
    }

(2)max()和 min()

    /**
     * Stream終止操作 2.max()和 min()
     * 查找最大值
     */
    public static void StreamMaxMin(){
        //返回數組最大值
        int[] nums = {11, 2, 32, 14, 5};
        int numMax = Arrays.stream(nums).max().getAsInt();
        int numMin = Arrays.stream(nums).min().getAsInt();
        System.out.println("數組最大值:"+numMax);
        System.out.println("數組最小值:"+numMin);

        //返回年紀最大值
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
        );
        Optional<User> userMax = users.stream().max((p, q) -> {
            return p.getAge().compareTo(q.getAge());
        });

        Optional<User> userMin = users.stream().min((p, q) -> {
            return p.getAge().compareTo(q.getAge());
        });
        System.out.println("年紀最大的是 : "+userMax.get());
        System.out.println("年紀最小的是 : "+userMin.get());

    }

(3)sum()和 average()

    /**
     * Stream終止操作 3.sum()和 average()
     * 查找最大值
     */
    public static void StreamSumAve(){
        //求和與平均值
        int[] nums = {11, 2, 32, 14, 5};
        int numSum = Arrays.stream(nums).sum();//求和
        double numAve = Arrays.stream(nums).average().getAsDouble();//求平均值
        System.out.println("求和 :"+numSum);
        System.out.println("平均值:"+numAve);

        //對象的求和與平均值
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
        );
        Integer userAgeSum = users.stream().map(u -> u.getAge()).reduce(Integer::sum).get();
        Double userAgeAve = users.stream().collect(Collectors.averagingInt(p -> p.getAge()));


        System.out.println("用戶年紀求和 : "+userAgeSum);
        System.out.println("用戶年紀平均值 : "+userAgeAve);

    }

Stream高級應用

下面是Stream的一些高級應用,個人覺得這個十分重要,像統計數據方面,真的是方便。

(1)排序並分組

    /**
     * Stream高級應用 1.排序並分組
     *
     */
    public static void StreamGroupingOrderBy(){
        try {
            SimpleDateFormat simFormat = new SimpleDateFormat("yyyy/MM/dd");
            //對象的求和與平均值
            List<User> users = Arrays.asList(
                    new User(1,"灰太狼",simFormat.parse("2018/01/23"),11,"男"),
                    new User(2,"紅太狼",simFormat.parse("2018/01/23"),10,"女"),
                    new User(2,"美羊羊",simFormat.parse("2001/12/03"),10,"女"),
                    new User(3,"小灰灰",simFormat.parse("2022/02/13"),15,"男"),
                    new User(3,"懶羊羊",simFormat.parse("2020/02/13"),15,"男")
            );

            //按性別分組
            Map<String, List<User>> collectSex = users.stream()
                    .sorted(Comparator.comparing(User::getBirthday))
                    .collect(Collectors.groupingBy(User::getSex));
            //輸出
            collectSex.forEach((k,v)->{
                System.out.println("key : "+k+"    value : "+v);
            });
            //按出生日期的day分組
            Map<Date, List<User>> collectBirthday= users.stream()
                    .sorted(Comparator.comparing(User::getBirthday))
                    .collect(Collectors.groupingBy(u->u.getBirthday()));

            //輸出
            collectBirthday.forEach((k,v)->{
                System.out.println("key : "+simFormat.format(k)+"    value : "+v);
            });




        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

(2)集合之間轉換

    /**
     * Stream高級應用 2.集合之間轉換
     *
     */
    public static void StreamConvert(){


        try {
            /**
             * List  ---->  Map
             */
            SimpleDateFormat simFormat = new SimpleDateFormat("yyyy/MM/dd");
            List<User> users = Arrays.asList(
                    new User(1,"灰太狼",simFormat.parse("2018/01/23"),11,"男"),
                    new User(2,"紅太狼",simFormat.parse("2018/01/23"),10,"女"),
                    new User(2,"美羊羊",simFormat.parse("2001/12/03"),10,"女"),
                    new User(3,"小灰灰",simFormat.parse("2022/02/13"),15,"男"),
                    new User(3,"懶羊羊",simFormat.parse("2020/02/13"),15,"男")
            );

            //以name爲key,age爲value,將list<User>轉爲Map
            Map<String, Integer> map = users.stream().collect(Collectors.toMap(User::getName, User::getAge));
           map.forEach((key,value)->{
               System.out.println("key:"+key+"    value:"+value);
           });



            /**
             * List  ----->  Set
             */
            Set<User> collect1 = users.stream().collect(Collectors.toSet());
            collect1.forEach(System.out::println);


            /**
             * Map  ----->  List
             */
            List<String> stringList = map.entrySet().stream().map(m -> m.getKey()).collect(Collectors.toList());
            stringList.forEach(System.out::println);

            /**
             * Map  ---->  Set
             */
            Set<String> stringSet = map.entrySet().stream().map(m -> m.getKey()).collect(Collectors.toSet());
            stringSet.forEach(System.out::println);


            /**
             * Set  ---->  List
             */
            List<String> list = stringSet.stream().collect(Collectors.toList());
            list.forEach(System.out::println);

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