函數式接口、Lambda表達式(Consumer、Supplier、Function、Predicate)【總結】

一、函數式接口
    1.什麼是函數式接口
        接口中只有一個抽象方法(不包括默認、靜態)

    2.如何去定義一個函數式接口
        @FunctionalInterface  註解的作用:約束接口中只能有一個抽象方法
        定義一個接口,提供一個抽象方法

    3.Lambda表達式格式
        (參數)      調用方法,傳遞參數
        ->          將小括號中參數傳遞到大括號中
        {}          實現代碼的方法體

    4.通過Lambda表達式輸出D盤下所有的.txt文件的名稱
        public class Demo01 {
            public static void main(String[] args) {
                File dir = new File("d:\\");

                print(dir);
            }

            public static void print(File dir) {
                File[] subFiles = dir.listFiles(pathname -> pathname.getName().endsWith(".txt") || pathname.isDirectory());

                if(subFiles != null) {
                    for(File subFile : subFiles) {
                        if(subFile.isDirectory()) {
                            print(subFile);
                        }else {
                            System.out.println(subFile.getName());
                        }
                    }
                }
            }
        }

    5.Lambda延遲加載機制
        //函數式接口
        @FunctionalInterface
            public interface MessageBuilder {
                //定義一個拼接消息的抽象方法,返回被拼接的消息
                public abstract String builderMessage();
            }

        //測試類
        public class Demo02Lambda {
            //定義一個顯示日誌的方法,方法的參數傳遞日誌的等級和MessageBuilder接口
            public static void showLog(int level, MessageBuilder mb){
                //對日誌的等級進行判斷,如果是1級,則調用MessageBuilder接口中的builderMessage方法
                if(level==1){
                    System.out.println(mb.builderMessage());
                }
            }

            public static void main(String[] args) {
                //定義三個日誌信息
                String msg1 = "Hello";
                String msg2 = "World";
                String msg3 = "Java";

                //調用showLog方法,參數MessageBuilder是一個函數式接口,所以可以傳遞Lambda表達式
                /*showLog(2,()->{
                    //返回一個拼接好的字符串
                    return  msg1+msg2+msg3;
                });*/

                /*
                    使用Lambda表達式作爲參數傳遞,僅僅是把參數傳遞到showLog方法中
                    只有滿足條件,日誌的等級是1級
                        纔會調用接口MessageBuilder中的方法builderMessage
                        纔會進行字符串的拼接
                    如果條件不滿足,日誌的等級不是1級
                        那麼MessageBuilder接口中的方法builderMessage也不會執行
                        所以拼接字符串的代碼也不會執行
                    所以不會存在性能的浪費
                 */
                showLog(2,()->{
                    System.out.println("不滿足條件不執行");
                    //返回一個拼接好的字符串
                    return  msg1+msg2+msg3;
                });
            }
        }

    6.函數式接口作爲方法的參數
        public class Demo01Runnable {
            //定義一個方法startThread,方法的參數使用函數式接口Runnable
            public static void startThread(Runnable run){
                //開啓多線程
                new Thread(run).start();
            }

            public static void main(String[] args) {
                //調用startThread方法,方法的參數是一個接口,那麼我們可以傳遞這個接口的匿名內部類
                startThread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName()+"-->"+"線程啓動了");
                    }
                });

                //調用startThread方法,方法的參數是一個函數式接口,所以可以傳遞Lambda表達式
                startThread(()->{
                    System.out.println(Thread.currentThread().getName()+"-->"+"線程啓動了");
                });

                //優化Lambda表達式
                startThread(()->System.out.println(Thread.currentThread().getName()+"-->"+"線程啓動了"));
            }
        }


    7.函數式接口作爲方法的返回值類型
        public class Demo02Comparator {
            //定義一個方法,方法的返回值類型使用函數式接口Comparator
            public static Comparator<String> getComparator(){
                //方法的返回值類型是一個接口,那麼我們可以返回這個接口的匿名內部類
                /*return new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        //按照字符串的降序排序
                        return o2.length()-o1.length();
                    }
                };*/

                //方法的返回值類型是一個函數式接口,所有我們可以返回一個Lambda表達式
                /*return (String o1, String o2)->{
                    //按照字符串的降序排序
                    return o2.length()-o1.length();
                };*/

                //繼續優化Lambda表達式
                return (o1, o2)->o2.length()-o1.length();
            }

            public static void main(String[] args) {
                //創建一個字符串數組
                String[] arr = {"aaa","b","cccccc","dddddddddddd"};
                //輸出排序前的數組
                System.out.println(Arrays.toString(arr));//[aaa, b, cccccc, dddddddddddd]
                //調用Arrays中的sort方法,對字符串數組進行排序
                Arrays.sort(arr,getComparator());
                //輸出排序後的數組
                System.out.println(Arrays.toString(arr));//[dddddddddddd, cccccc, aaa, b]
            }
        }

二、常用的函數式接口
    1.Supplier<T>函數式接口-用來做生產的
        T get();

        示例代碼:
            public class Demo01Supplier {
                //定義一個方法,方法的參數傳遞Supplier<T>接口,泛型執行String,get方法就會返回一個String
                public static String getString(Supplier<String> sup){
                    return sup.get();
                }

                public static void main(String[] args) {
                    //調用getString方法,方法的參數Supplier是一個函數式接口,所以可以傳遞Lambda表達式
                    String s = getString(()->{
                        //生產一個字符串,並返回
                        return "胡歌";
                    });
                    System.out.println(s);

                    //優化Lambda表達式
                    String s2 = getString(()->"胡歌");
                    System.out.println(s2);
                }
            }

        使用Supplier接口中的get方法。來獲取數組中的最大值
            public class Demo02Test {
               //定義一個方法,用於獲取int類型數組中元素的最大值,方法的參數傳遞Supplier接口,泛型使用Integer
               public static int getMax(Supplier<Integer> sup){
                   return sup.get();
               }

                public static void main(String[] args) {
                    //定義一個int類型的數組,並賦值
                    int[] arr = {100,0,-50,880,99,33,-30};
                    //調用getMax方法,方法的參數Supplier是一個函數式接口,所以可以傳遞Lambda表達式
                    int maxValue = getMax(()->{
                        //獲取數組的最大值,並返回
                        //定義一個變量,把數組中的第一個元素賦值給該變量,記錄數組中元素的最大值
                        int max = arr[0];
                        //遍歷數組,獲取數組中的其他元素
                        for (int i : arr) {
                            //使用其他的元素和最大值比較
                            if(i>max){
                                //如果i大於max,則替換max作爲最大值
                                max = i;
                            }
                        }
                        //返回最大值
                        return max;
                    });
                    System.out.println("數組中元素的最大值是:"+maxValue);
                }
            }

    2.Consumer<T t>函數式接口-用來做消費的
        void accept(T t);
        示例代碼:
            public class Demo01Consumer {
                /*
                    定義一個方法
                    方法的參數傳遞一個字符串的姓名
                    方法的參數傳遞Consumer接口,泛型使用String
                    可以使用Consumer接口消費字符串的姓名
                 */
                public static void method(String name, Consumer<String> con){
                    con.accept(name);
                }

                public static void main(String[] args) {
                    //調用method方法,傳遞字符串姓名,方法的另一個參數是Consumer接口,是一個函數式接口,所以可以傳遞Lambda表達式
                    method("趙麗穎",(String name)->{
                        //對傳遞的字符串進行消費
                        //消費方式:直接輸出字符串
                        //System.out.println(name);

                        //消費方式:把字符串進行反轉輸出
                        String reName = new StringBuffer(name).reverse().toString();
                        System.out.println(reName);
                    });
                }
            }


        andThen(Consumer<T t>);
        示例代碼:
            public class Demo02AndThen {
                //定義一個方法,方法的參數傳遞一個字符串和兩個Consumer接口,Consumer接口的泛型使用字符串
                public static void method(String s, Consumer<String> con1, Consumer<String> con2){
                    //con1.accept(s);
                    //con2.accept(s);

                    //使用andThen方法,把兩個Consumer接口連接到一起,在消費數據
                    con1.andThen(con2).accept(s);//con1連接con2,先執行con1消費數據,在執行con2消費數據
                }

                public static void main(String[] args) {
                    //調用method方法,傳遞一個字符串,兩個Lambda表達式
                    method("Hello",
                            (t)->{
                                //消費方式:把字符串轉換爲大寫輸出
                                System.out.println(t.toUpperCase());
                            },
                            (t)->{
                                //消費方式:把字符串轉換爲小寫輸出
                                System.out.println(t.toLowerCase());
                            });
                }
            }

        字符串拼接案例
            public class Demo03Test {
                //定義一個方法,參數傳遞String類型的數組和兩個Consumer接口,泛型使用String
                public static void printInfo(String[] arr, Consumer<String> con1,Consumer<String> con2){
                    //遍歷字符串數組
                    for (String message : arr) {
                        //使用andThen方法連接兩個Consumer接口,消費字符串
                        con1.andThen(con2).accept(message);
                        /*con1.accept(message);
                        con2.accept(message);*/
                    }
                }

                public static void main(String[] args) {
                    //定義一個字符串類型的數組
                    String[] arr = { "迪麗熱巴,女", "古力娜扎,女", "馬爾扎哈,男" };

                    //調用printInfo方法,傳遞一個字符串數組,和兩個Lambda表達式
                    printInfo(arr,(message)->{
                        //消費方式:對message進行切割,獲取姓名,按照指定的格式輸出
                        String name = message.split(",")[0];
                        System.out.print("姓名: "+name);
                    },(message)->{
                        //消費方式:對message進行切割,獲取年齡,按照指定的格式輸出
                        String sex = message.split(",")[1];
                        System.out.println("。性別: "+sex+"。");
                    });

                }
            }

    3.Predicate<T>函數式接口      
        boolean test(T t);  獲取布爾類型結果
        示例代碼:
            public class Demo01Predicate {
            /*
                定義一個方法
                參數傳遞一個String類型的字符串
                傳遞一個Predicate接口,泛型使用String
                使用Predicate中的方法test對字符串進行判斷,並把判斷的結果返回
             */
            public static boolean checkString(String s, Predicate<String> pre){
                return  pre.test(s);
            }

            public static void main(String[] args) {
                //定義一個字符串
                String s = "abcdef";

                //調用checkString方法對字符串進行校驗,參數傳遞字符串和Lambda表達式
                /*boolean b = checkString(s,(String str)->{
                    //對參數傳遞的字符串進行判斷,判斷字符串的長度是否大於5,並把判斷的結果返回
                    return str.length()>5;
                });*/

                //優化Lambda表達式
                boolean b = checkString(s,str->str.length()>5);
                System.out.println(b);
            }
        }

        and();   代表&&的意思
        示例代碼:
            public class Demo02Predicate_and {
            /*
                定義一個方法,方法的參數,傳遞一個字符串
                傳遞兩個Predicate接口
                    一個用於判斷字符串的長度是否大於5
                    一個用於判斷字符串中是否包含a
                    兩個條件必須同時滿足
             */
            public static boolean checkString(String s, Predicate<String> pre1,Predicate<String> pre2){
                //return pre1.test(s) && pre2.test(s);
                return pre1.and(pre2).test(s);//等價於return pre1.test(s) && pre2.test(s);
            }

            public static void main(String[] args) {
                //定義一個字符串
                String s = "abcdef";
                //調用checkString方法,參數傳遞字符串和兩個Lambda表達式
                boolean b = checkString(s,(String str)->{
                    //判斷字符串的長度是否大於5
                    return str.length()>5;
                },(String str)->{
                    //判斷字符串中是否包含a
                    return str.contains("a");
                });
                System.out.println(b);
            }
        }

        or();   代表||的意思
        示例代碼:
            public class Demo03Predicate_or {
            /*
                    定義一個方法,方法的參數,傳遞一個字符串
                    傳遞兩個Predicate接口
                        一個用於判斷字符串的長度是否大於5
                        一個用於判斷字符串中是否包含a
                        滿足一個條件即可
                 */
            public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
                //return pre1.test(s) || pre2.test(s);
                return  pre1.or(pre2).test(s);//等價於return pre1.test(s) || pre2.test(s);
            }

            public static void main(String[] args) {
                //定義一個字符串
                String s = "bc";
                //調用checkString方法,參數傳遞字符串和兩個Lambda表達式
                boolean b = checkString(s,(String str)->{
                    //判斷字符串的長度是否大於5
                    return str.length()>5;
                },(String str)->{
                    //判斷字符串中是否包含a
                    return str.contains("a");
                });
                System.out.println(b);
            }
        }

        negate();  代表的是取反
        示例代碼:
            public class Demo04Predicate_negate {
                /*
                       定義一個方法,方法的參數,傳遞一個字符串
                       使用Predicate接口判斷字符串的長度是否大於5
                */
                public static boolean checkString(String s, Predicate<String> pre){
                    //return !pre.test(s);
                    return  pre.negate().test(s);//等效於return !pre.test(s);
                }

                public static void main(String[] args) {
                    //定義一個字符串
                    String s = "abc";
                    //調用checkString方法,參數傳遞字符串和Lambda表達式
                    boolean b = checkString(s,(String str)->{
                        //判斷字符串的長度是否大於5,並返回結果
                        return str.length()>5;
                    });
                    System.out.println(b);
                }
            }

        案例-將滿足條件的字符串保存到集合中
            public class Demo05Test {
                /*
                    定義一個方法
                    方法的參數傳遞一個包含人員信息的數組
                    傳遞兩個Predicate接口,用於對數組中的信息進行過濾
                    把滿足條件的信息存到ArrayList集合中並返回
                 */
                public static ArrayList<String> filter(String[] arr,Predicate<String> pre1,Predicate<String> pre2){
                    //定義一個ArrayList集合,存儲過濾之後的信息
                    ArrayList<String> list = new ArrayList<>();
                    //遍歷數組,獲取數組中的每一條信息
                    for (String s : arr) {
                        //使用Predicate接口中的方法test對獲取到的字符串進行判斷
                        boolean b = pre1.and(pre2).test(s);
                        //對得到的布爾值進行判斷
                        if(b){
                            //條件成立,兩個條件都滿足,把信息存儲到ArrayList集合中
                            list.add(s);
                        }
                    }
                    //把集合返回
                    return list;
                }

                public static void main(String[] args) {
                    //定義一個儲存字符串的數組
                    String[] array = { "迪麗熱巴,女", "古力娜扎,女", "馬爾扎哈,男", "趙麗穎,女" };
                    //調用filter方法,傳遞字符串數組和兩個Lambda表達式
                    ArrayList<String> list = filter(array,(String s)->{
                        //獲取字符串中的性別,判斷是否爲女
                       return s.split(",")[1].equals("女");
                    },(String s)->{
                        //獲取字符串中的姓名,判斷長度是否爲4個字符
                       return s.split(",")[0].length()==4;
                    });
                    //遍歷集合
                    for (String s : list) {
                        System.out.println(s);
                    }
                }
            }

    4.Function<T t,R r>函數式接口
        R apply(T t);    數據類型轉換
        public class Demo01Function {
            /*
                定義一個方法
                方法的參數傳遞一個字符串類型的整數
                方法的參數傳遞一個Function接口,泛型使用<String,Integer>
                使用Function接口中的方法apply,把字符串類型的整數,轉換爲Integer類型的整數
             */
            public static void change(String s, Function<String,Integer> fun){
                //Integer in = fun.apply(s);
                int in = fun.apply(s);//自動拆箱 Integer->int
                System.out.println(in);
            }

            public static void main(String[] args) {
                //定義一個字符串類型的整數
                String s = "1234";
                //調用change方法,傳遞字符串類型的整數,和Lambda表達式
                change(s,(String str)->{
                    //把字符串類型的整數,轉換爲Integer類型的整數返回
                    return Integer.parseInt(str);
                });
                //優化Lambda
                change(s,str->Integer.parseInt(str));
            }
        }

        andThen(Function<T t,R r>);
        示例代碼:
            public class Demo02Function_andThen {
            /*
                定義一個方法
                參數串一個字符串類型的整數
                參數再傳遞兩個Function接口
                    一個泛型使用Function<String,Integer>
                    一個泛型使用Function<Integer,String>
             */
            public static void change(String s, Function<String,Integer> fun1,Function<Integer,String> fun2){
                String ss = fun1.andThen(fun2).apply(s);
                System.out.println(ss);
            }

            public static void main(String[] args) {
                //定義一個字符串類型的整數
                String s = "123";
                //調用change方法,傳遞字符串和兩個Lambda表達式
                change(s,(String str)->{
                    //把字符串轉換爲整數+10
                    return Integer.parseInt(str)+10;
                },(Integer i)->{
                    //把整數轉換爲字符串
                    return i+"";
                });

                //優化Lambda表達式
                change(s,str->Integer.parseInt(str)+10,i->i+"");
            }
        }

     Function接口的案例
     public class Demo03Test {
        /*
            定義一個方法
            參數傳遞包含姓名和年齡的字符串
            參數再傳遞3個Function接口用於類型轉換
         */
        public static int change(String s, Function<String,String> fun1,
                                 Function<String,Integer> fun2,Function<Integer,Integer> fun3){
            //使用andThen方法把三個轉換組合到一起
            return fun1.andThen(fun2).andThen(fun3).apply(s);
        }

        public static void main(String[] args) {
            //定義一個字符串
            String str = "趙麗穎,20";
            //調用change方法,參數傳遞字符串和3個Lambda表達式
            int num = change(str,(String s)->{
                //"趙麗穎,20"->"20"
               return s.split(",")[1];
            },(String s)->{
                //"20"->20
                return Integer.parseInt(s);
            },(Integer i)->{
                //20->120
                return i+100;
            });
            System.out.println(num);
        }
    }

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