Java 不可變集合 Stream流以及方法引用

瑪拉_以琳發表於2023-04-26

1.不可變集合

1.1 什麼是不可變集合

​ 是一個長度不可變,內容也無法修改的集合

1.2 使用場景

​ 如果某個資料不能被修改,把它防禦性地複製到不可變集合中是個很好的實踐。

​ 當集合物件被不可信的庫呼叫時,不可變形式是安全的。

簡單理解:

​ 不想讓別人修改集合中的內容

比如說:

1,鬥地主的54張牌,是不能新增,不能刪除,不能修改的

2,鬥地主的打牌規則:單張,對子,三張,順子等,也是不能修改的

3,用程式碼獲取的作業系統硬體資訊,也是不能被修改的

1.3 不可變集合分類

  • 不可變的list集合
  • 不可變的set集合
  • 不可變的map集合

1.4 不可變的list集合

public class ImmutableDemo1 {
    public static void main(String[] args) {
        /*
            建立不可變的List集合
            "張三", "李四", "王五", "趙六"
        */

        //一旦建立完畢之後,是無法進行修改的,在下面的程式碼中,只能進行查詢操作
        List<String> list = List.of("張三", "李四", "王五", "趙六");

        System.out.println(list.get(0));
        System.out.println(list.get(1));
        System.out.println(list.get(2));
        System.out.println(list.get(3));

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

        for (String s : list) {
            System.out.println(s);
        }

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


        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("---------------------------");

        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }
        System.out.println("---------------------------");

        //list.remove("李四");
        //list.add("aaa");
        list.set(0,"aaa");
    }
}

1.5 不可變的Set集合

public class ImmutableDemo2 {
    public static void main(String[] args) {
        /*
           建立不可變的Set集合
           "張三", "李四", "王五", "趙六"


           細節:
                當我們要獲取一個不可變的Set集合時,裡面的引數一定要保證唯一性
        */

        //一旦建立完畢之後,是無法進行修改的,在下面的程式碼中,只能進行查詢操作
        Set<String> set = Set.of("張三", "張三", "李四", "王五", "趙六");

        for (String s : set) {
            System.out.println(s);
        }

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

        Iterator<String> it = set.iterator();
        while(it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }

        System.out.println("-----------------------");
        //set.remove("王五");
    }
}

1.6 不可變的Map集合

1.6.1:鍵值對個數小於等於10

public class ImmutableDemo3 {
    public static void main(String[] args) {
       /*
        建立Map的不可變集合
            細節1:
                鍵是不能重複的
            細節2:
                Map裡面的of方法,引數是有上限的,最多隻能傳遞20個引數,10個鍵值對
            細節3:
                如果我們要傳遞多個鍵值對物件,數量大於10個,在Map介面中還有一個方法
        */

        //一旦建立完畢之後,是無法進行修改的,在下面的程式碼中,只能進行查詢操作
        Map<String, String> map = Map.of("張三", "南京", "張三", "北京", "王五", "上海",
                "趙六", "廣州", "孫七", "深圳", "周八", "杭州",
                "吳九", "寧波", "鄭十", "蘇州", "劉一", "無錫",
                "陳二", "嘉興");

        Set<String> keys = map.keySet();
        for (String key : keys) {
            String value = map.get(key);
            System.out.println(key + "=" + value);
        }

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

        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }
        System.out.println("--------------------------");
    }
}

1.6.2:鍵值對個數大於10

public class ImmutableDemo4 {
    public static void main(String[] args) {

        /*
            建立Map的不可變集合,鍵值對的數量超過10個
        */

        //1.建立一個普通的Map集合
        HashMap<String, String> hm = new HashMap<>();
        hm.put("張三", "南京");
        hm.put("李四", "北京");
        hm.put("王五", "上海");
        hm.put("趙六", "北京");
        hm.put("孫七", "深圳");
        hm.put("周八", "杭州");
        hm.put("吳九", "寧波");
        hm.put("鄭十", "蘇州");
        hm.put("劉一", "無錫");
        hm.put("陳二", "嘉興");
        hm.put("aaa", "111");

        //2.利用上面的資料來獲取一個不可變的集合
/*
        //獲取到所有的鍵值對物件(Entry物件)
        Set<Map.Entry<String, String>> entries = hm.entrySet();
        //把entries變成一個陣列
        Map.Entry[] arr1 = new Map.Entry[0];
        //toArray方法在底層會比較集合的長度跟陣列的長度兩者的大小
        //如果集合的長度 > 陣列的長度 :資料在陣列中放不下,此時會根據實際資料的個數,重新建立陣列
        //如果集合的長度 <= 陣列的長度:資料在陣列中放的下,此時不會建立新的陣列,而是直接用
        Map.Entry[] arr2 = entries.toArray(arr1);
        //不可變的map集合
        Map map = Map.ofEntries(arr2);
        map.put("bbb","222");*/


        //Map<Object, Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));

        Map<String, String> map = Map.copyOf(hm);
        map.put("bbb","222");
    }
}

2.Stream流

2.1體驗Stream流

  • 案例需求

    按照下面的要求完成集合的建立和遍歷

    • 建立一個集合,儲存多個字串元素
    • 把集合中所有以"張"開頭的元素儲存到一個新的集合
    • 把"張"開頭的集合中的長度為3的元素儲存到一個新的集合
    • 遍歷上一步得到的集合
  • 原始方式示例程式碼

    public class MyStream1 {
        public static void main(String[] args) {
            //集合的批次新增
            ArrayList<String> list1 = new ArrayList<>(List.of("張三丰","張無忌","張翠山","王二麻子","張良","謝廣坤"));
            //list.add()
    
            //遍歷list1把以張開頭的元素新增到list2中。
            ArrayList<String> list2 = new ArrayList<>();
            for (String s : list1) {
                if(s.startsWith("張")){
                    list2.add(s);
                }
            }
            //遍歷list2集合,把其中長度為3的元素,再新增到list3中。
            ArrayList<String> list3 = new ArrayList<>();
            for (String s : list2) {
                if(s.length() == 3){
                    list3.add(s);
                }
            }
            for (String s : list3) {
                System.out.println(s);
            }      
        }
    }
  • 使用Stream流示例程式碼

    public class StreamDemo {
        public static void main(String[] args) {
            //集合的批次新增
            ArrayList<String> list1 = new ArrayList<>(List.of("張三丰","張無忌","張翠山","王二麻子","張良","謝廣坤"));
    
            //Stream流
            list1.stream().filter(s->s.startsWith("張"))
                    .filter(s->s.length() == 3)
                    .forEach(s-> System.out.println(s));
        }
    }
  • Stream流的好處

    • 直接閱讀程式碼的字面意思即可完美展示無關邏輯方式的語義:獲取流、過濾姓張、過濾長度為3、逐一列印
    • Stream流把真正的函數語言程式設計風格引入到Java中
    • 程式碼簡潔

2.2Stream流的常見生成方式

  • Stream流的思想

01_Stream流思想.png

  • Stream流的三類方法

    • 獲取Stream流

      • 建立一條流水線,並把資料放到流水線上準備進行操作
    • 中間方法

      • 流水線上的操作
      • 一次操作完畢之後,還可以繼續進行其他操作
    • 終結方法

      • 一個Stream流只能有一個終結方法
      • 是流水線上的最後一個操作
  • 生成Stream流的方式

    • Collection體系集合

      使用預設方法stream()生成流, default Stream<E> stream()

    • Map體系集合

      把Map轉成Set集合,間接的生成流

    • 陣列

      透過Arrays中的靜態方法stream生成流

    • 同種資料型別的多個資料

      透過Stream介面的靜態方法of(T... values)生成流

  • 程式碼演示

    public class StreamDemo {
        public static void main(String[] args) {
            //Collection體系的集合可以使用預設方法stream()生成流
            List<String> list = new ArrayList<String>();
            Stream<String> listStream = list.stream();
    
            Set<String> set = new HashSet<String>();
            Stream<String> setStream = set.stream();
    
            //Map體系的集合間接的生成流
            Map<String,Integer> map = new HashMap<String, Integer>();
            Stream<String> keyStream = map.keySet().stream();
            Stream<Integer> valueStream = map.values().stream();
            Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
    
            //陣列可以透過Arrays中的靜態方法stream生成流
            String[] strArray = {"hello","world","java"};
            Stream<String> strArrayStream = Arrays.stream(strArray);
          
              //同種資料型別的多個資料可以透過Stream介面的靜態方法of(T... values)生成流
            Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
            Stream<Integer> intStream = Stream.of(10, 20, 30);
        }
    }

2.3Stream流中間操作方法

  • 概念

    中間操作的意思是,執行完此方法之後,Stream流依然可以繼續執行其他操作

  • 常見方法

    方法名說明
    Stream<T> filter(Predicate predicate)用於對流中的資料進行過濾
    Stream<T> limit(long maxSize)返回此流中的元素組成的流,擷取前指定引數個數的資料
    Stream<T> skip(long n)跳過指定引數個數的資料,返回由該流的剩餘元素組成的流
    static <T> Stream<T> concat(Stream a, Stream b)合併a和b兩個流為一個流
    Stream<T> distinct()返回由該流的不同元素(根據Object.equals(Object) )組成的流
  • filter程式碼演示

    public class MyStream3 {
        public static void main(String[] args) {
    //        Stream<T> filter(Predicate predicate):過濾
    //        Predicate介面中的方法    boolean test(T t):對給定的引數進行判斷,返回一個布林值
    
            ArrayList<String> list = new ArrayList<>();
            list.add("張三丰");
            list.add("張無忌");
            list.add("張翠山");
            list.add("王二麻子");
            list.add("張良");
            list.add("謝廣坤");
    
            //filter方法獲取流中的 每一個資料.
            //而test方法中的s,就依次表示流中的每一個資料.
            //我們只要在test方法中對s進行判斷就可以了.
            //如果判斷的結果為true,則當前的資料留下
            //如果判斷的結果為false,則當前資料就不要.
    //        list.stream().filter(
    //                new Predicate<String>() {
    //                    @Override
    //                    public boolean test(String s) {
    //                        boolean result = s.startsWith("張");
    //                        return result;
    //                    }
    //                }
    //        ).forEach(s-> System.out.println(s));
    
            //因為Predicate介面中只有一個抽象方法test
            //所以我們可以使用lambda表示式來簡化
    //        list.stream().filter(
    //                (String s)->{
    //                    boolean result = s.startsWith("張");
    //                        return result;
    //                }
    //        ).forEach(s-> System.out.println(s));
    
            list.stream().filter(s ->s.startsWith("張")).forEach(s-> System.out.println(s));
    
        }
    }
  • limit&skip程式碼演示

    public class StreamDemo02 {
        public static void main(String[] args) {
            //建立一個集合,儲存多個字串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("張曼玉");
            list.add("王祖賢");
            list.add("柳巖");
            list.add("張敏");
            list.add("張無忌");
    
            //需求1:取前3個資料在控制檯輸出
            list.stream().limit(3).forEach(s-> System.out.println(s));
            System.out.println("--------");
    
            //需求2:跳過3個元素,把剩下的元素在控制檯輸出
            list.stream().skip(3).forEach(s-> System.out.println(s));
            System.out.println("--------");
    
            //需求3:跳過2個元素,把剩下的元素中前2個在控制檯輸出
            list.stream().skip(2).limit(2).forEach(s-> System.out.println(s));
        }
    }
  • concat&distinct程式碼演示

    public class StreamDemo03 {
        public static void main(String[] args) {
            //建立一個集合,儲存多個字串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("張曼玉");
            list.add("王祖賢");
            list.add("柳巖");
            list.add("張敏");
            list.add("張無忌");
    
            //需求1:取前4個資料組成一個流
            Stream<String> s1 = list.stream().limit(4);
    
            //需求2:跳過2個資料組成一個流
            Stream<String> s2 = list.stream().skip(2);
    
            //需求3:合併需求1和需求2得到的流,並把結果在控制檯輸出
    //        Stream.concat(s1,s2).forEach(s-> System.out.println(s));
    
            //需求4:合併需求1和需求2得到的流,並把結果在控制檯輸出,要求字串元素不能重複
            Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s));
        }
    }

2.4Stream流終結操作方法

  • 概念

    終結操作的意思是,執行完此方法之後,Stream流將不能再執行其他操作

  • 常見方法

    方法名說明
    void forEach(Consumer action)對此流的每個元素執行操作
    long count()返回此流中的元素數
  • 程式碼演示

    public class MyStream5 {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<>();
            list.add("張三丰");
            list.add("張無忌");
            list.add("張翠山");
            list.add("王二麻子");
            list.add("張良");
            list.add("謝廣坤");
    
            //method1(list);
            
    //        long count():返回此流中的元素數
            long count = list.stream().count();
            System.out.println(count);
        }
    
        private static void method1(ArrayList<String> list) {
            //  void forEach(Consumer action):對此流的每個元素執行操作
            //  Consumer介面中的方法void accept(T t):對給定的引數執行此操作
            //在forEach方法的底層,會迴圈獲取到流中的每一個資料.
            //並迴圈呼叫accept方法,並把每一個資料傳遞給accept方法
            //s就依次表示了流中的每一個資料.
            //所以,我們只要在accept方法中,寫上處理的業務邏輯就可以了.
            list.stream().forEach(
                    new Consumer<String>() {
                        @Override
                        public void accept(String s) {
                            System.out.println(s);
                        }
                    }
            );
          
            System.out.println("====================");
            //lambda表示式的簡化格式
            //是因為Consumer介面中,只有一個accept方法
            list.stream().forEach(
                    (String s)->{
                        System.out.println(s);
                    }
            );
            System.out.println("====================");
            //lambda表示式還是可以進一步簡化的.
            list.stream().forEach(s->System.out.println(s));
        }
    }

2.5Stream流的收集操作

  • 概念

    對資料使用Stream流的方式操作完畢後,可以把流中的資料收集到集合中

  • 常用方法

    方法名說明
    R collect(Collector collector)把結果收集到集合中
  • 工具類Collectors提供了具體的收集方式

    方法名說明
    public static <T> Collector toList()把元素收集到List集合中
    public static <T> Collector toSet()把元素收集到Set集合中
    public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中
  • 程式碼演示

    // toList和toSet方法演示 
    public class MyStream7 {
        public static void main(String[] args) {
            ArrayList<Integer> list1 = new ArrayList<>();
            for (int i = 1; i <= 10; i++) {
                list1.add(i);
            }
    
            list1.add(10);
            list1.add(10);
            list1.add(10);
            list1.add(10);
            list1.add(10);
    
            //filter負責過濾資料的.
            //collect負責收集資料.
                    //獲取流中剩餘的資料,但是他不負責建立容器,也不負責把資料新增到容器中.
            //Collectors.toList() : 在底層會建立一個List集合.並把所有的資料新增到List集合中.
            List<Integer> list = list1.stream().filter(number -> number % 2 == 0)
                    .collect(Collectors.toList());
    
            System.out.println(list);
    
        Set<Integer> set = list1.stream().filter(number -> number % 2 == 0)
                .collect(Collectors.toSet());
        System.out.println(set);
    }
    }
    /**
    Stream流的收集方法 toMap方法演示
    建立一個ArrayList集合,並新增以下字串。字串中前面是姓名,後面是年齡
    "zhangsan,23"
    "lisi,24"
    "wangwu,25"
    保留年齡大於等於24歲的人,並將結果收集到Map集合中,姓名為鍵,年齡為值
    */
    public class MyStream8 {
        public static void main(String[] args) {
              ArrayList<String> list = new ArrayList<>();
            list.add("zhangsan,23");
            list.add("lisi,24");
            list.add("wangwu,25");
    
            Map<String, Integer> map = list.stream().filter(
                    s -> {
                        String[] split = s.split(",");
                        int age = Integer.parseInt(split[1]);
                        return age >= 24;
                    }
    
             //   collect方法只能獲取到流中剩餘的每一個資料.
             //在底層不能建立容器,也不能把資料新增到容器當中
    
             //Collectors.toMap 建立一個map集合並將資料新增到集合當中
    
              // s 依次表示流中的每一個資料
    
              //第一個lambda表示式就是如何獲取到Map中的鍵
              //第二個lambda表示式就是如何獲取Map中的值
            ).collect(Collectors.toMap(
                    s -> s.split(",")[0],
                    s -> Integer.parseInt(s.split(",")[1]) ));
    
            System.out.println(map);
        }
    }

2.6Stream流綜合練習

  • 案例需求

    現在有兩個ArrayList集合,分別儲存6名男演員名稱和6名女演員名稱,要求完成如下的操作

    • 男演員只要名字為3個字的前三人
    • 女演員只要姓林的,並且不要第一個
    • 把過濾後的男演員姓名和女演員姓名合併到一起
    • 把上一步操作後的元素作為構造方法的引數建立演員物件,遍歷資料

    演員類Actor已經提供,裡面有一個成員變數,一個帶參構造方法,以及成員變數對應的get/set方法

  • 程式碼實現

    演員類

    public class Actor {
        private String name;
    
        public Actor(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    測試類

    public class StreamTest {
        public static void main(String[] args) {
            //建立集合
            ArrayList<String> manList = new ArrayList<String>();
            manList.add("周潤發");
            manList.add("成龍");
            manList.add("劉德華");
            manList.add("吳京");
            manList.add("周星馳");
            manList.add("李連杰");
      
            ArrayList<String> womanList = new ArrayList<String>();
            womanList.add("林心如");
            womanList.add("張曼玉");
            womanList.add("林青霞");
            womanList.add("柳巖");
            womanList.add("林志玲");
            womanList.add("王祖賢");
      
            //男演員只要名字為3個字的前三人
            Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3);
      
            //女演員只要姓林的,並且不要第一個
            Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);
      
            //把過濾後的男演員姓名和女演員姓名合併到一起
            Stream<String> stream = Stream.concat(manStream, womanStream);
      
              // 將流中的資料封裝成Actor物件之後列印
              stream.forEach(name -> {
                Actor actor = new Actor(name);
                System.out.println(actor);
            }); 
        }
    }

3.方法引用

3.1體驗方法引用

  • 方法引用的出現原因

    在使用Lambda表示式的時候,我們實際上傳遞進去的程式碼就是一種解決方案:拿引數做操作

    那麼考慮一種情況:如果我們在Lambda中所指定的操作方案,已經有地方存在相同方案,那是否還有必要再寫重複邏輯呢?答案肯定是沒有必要

    那我們又是如何使用已經存在的方案的呢?

    這就是我們要講解的方法引用,我們是透過方法引用來使用已經存在的方案

  • 程式碼演示

    public interface Printable {
        void printString(String s);
    }
    
    public class PrintableDemo {
        public static void main(String[] args) {
            //在主方法中呼叫usePrintable方法
    //        usePrintable((String s) -> {
    //            System.out.println(s);
    //        });
            //Lambda簡化寫法
            usePrintable(s -> System.out.println(s));
    
            //方法引用
            usePrintable(System.out::println);
    
        }
    
        private static void usePrintable(Printable p) {
            p.printString("愛生活愛Java");
        }
    }
    

3.2方法引用符

  • 方法引用符

    :: 該符號為引用運算子,而它所在的表示式被稱為方法引用

  • 推導與省略

    • 如果使用Lambda,那麼根據“可推導就是可省略”的原則,無需指定引數型別,也無需指定的過載形式,它們都將被自動推導
    • 如果使用方法引用,也是同樣可以根據上下文進行推導
    • 方法引用是Lambda的孿生兄弟

3.3引用類方法

​ 引用類方法,其實就是引用類的靜態方法

  • 格式

    類名::靜態方法

  • 範例

    Integer::parseInt

    Integer類的方法:public static int parseInt(String s) 將此String轉換為int型別資料

  • 練習描述

    • 定義一個介面(Converter),裡面定義一個抽象方法 int convert(String s);
    • 定義一個測試類(ConverterDemo),在測試類中提供兩個方法

      • 一個方法是:useConverter(Converter c)
      • 一個方法是主方法,在主方法中呼叫useConverter方法
  • 程式碼演示

    public interface Converter {
        int convert(String s);
    }
    
    public class ConverterDemo {
        public static void main(String[] args) {
    
            //Lambda寫法
            useConverter(s -> Integer.parseInt(s));
    
            //引用類方法
            useConverter(Integer::parseInt);
    
        }
    
        private static void useConverter(Converter c) {
            int number = c.convert("666");
            System.out.println(number);
        }
    }
  • 使用說明

    Lambda表示式被類方法替代的時候,它的形式引數全部傳遞給靜態方法作為引數

3.4引用物件的例項方法

​ 引用物件的例項方法,其實就引用類中的成員方法

  • 格式

    物件::成員方法

  • 範例

    "HelloWorld"::toUpperCase

    String類中的方法:public String toUpperCase() 將此String所有字元轉換為大寫

  • 練習描述

    • 定義一個類(PrintString),裡面定義一個方法

      public void printUpper(String s):把字串引數變成大寫的資料,然後在控制檯輸出

    • 定義一個介面(Printer),裡面定義一個抽象方法

      void printUpperCase(String s)

    • 定義一個測試類(PrinterDemo),在測試類中提供兩個方法

      • 一個方法是:usePrinter(Printer p)
      • 一個方法是主方法,在主方法中呼叫usePrinter方法
  • 程式碼演示

    public class PrintString {
        //把字串引數變成大寫的資料,然後在控制檯輸出
        public void printUpper(String s) {
            String result = s.toUpperCase();
            System.out.println(result);
        }
    }
    
    public interface Printer {
        void printUpperCase(String s);
    }
    
    public class PrinterDemo {
        public static void main(String[] args) {
    
            //Lambda簡化寫法
            usePrinter(s -> System.out.println(s.toUpperCase()));
    
            //引用物件的例項方法
            PrintString ps = new PrintString();
            usePrinter(ps::printUpper);
    
        }
    
        private static void usePrinter(Printer p) {
            p.printUpperCase("HelloWorld");
        }
    }
    
  • 使用說明

    Lambda表示式被物件的例項方法替代的時候,它的形式引數全部傳遞給該方法作為引數

3.5引用類的例項方法

​ 引用類的例項方法,其實就是引用類中的成員方法

  • 格式

    類名::成員方法

  • 範例

    String::substring

    public String substring(int beginIndex,int endIndex)

    從beginIndex開始到endIndex結束,擷取字串。返回一個子串,子串的長度為endIndex-beginIndex

  • 練習描述

    • 定義一個介面(MyString),裡面定義一個抽象方法:

      String mySubString(String s,int x,int y);

    • 定義一個測試類(MyStringDemo),在測試類中提供兩個方法

      • 一個方法是:useMyString(MyString my)
      • 一個方法是主方法,在主方法中呼叫useMyString方法
  • 程式碼演示

    public interface MyString {
        String mySubString(String s,int x,int y);
    }
    
    public class MyStringDemo {
        public static void main(String[] args) {
            //Lambda簡化寫法
            useMyString((s,x,y) -> s.substring(x,y));
    
            //引用類的例項方法
            useMyString(String::substring);
    
        }
    
        private static void useMyString(MyString my) {
            String s = my.mySubString("HelloWorld", 2, 5);
            System.out.println(s);
        }
    }
  • 使用說明

    ​ Lambda表示式被類的例項方法替代的時候
    ​ 第一個引數作為呼叫者
    ​ 後面的引數全部傳遞給該方法作為引數

3.6引用構造器

​ 引用構造器,其實就是引用構造方法

  • l格式

    類名::new

  • 範例

    Student::new

  • 練習描述

    • 定義一個類(Student),裡面有兩個成員變數(name,age)

      並提供無參構造方法和帶參構造方法,以及成員變數對應的get和set方法

    • 定義一個介面(StudentBuilder),裡面定義一個抽象方法

      Student build(String name,int age);

    • 定義一個測試類(StudentDemo),在測試類中提供兩個方法

      • 一個方法是:useStudentBuilder(StudentBuilder s)
      • 一個方法是主方法,在主方法中呼叫useStudentBuilder方法
  • 程式碼演示

    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    public interface StudentBuilder {
        Student build(String name,int age);
    }
    
    public class StudentDemo {
        public static void main(String[] args) {
    
            //Lambda簡化寫法
            useStudentBuilder((name,age) -> new Student(name,age));
    
            //引用構造器
            useStudentBuilder(Student::new);
    
        }
    
        private static void useStudentBuilder(StudentBuilder sb) {
            Student s = sb.build("林青霞", 30);
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
  • 使用說明

    Lambda表示式被構造器替代的時候,它的形式引數全部傳遞給構造器作為引數

相關文章