1. 程式人生 > >函式式介面、Lambda表示式(Consumer、Supplier、Function、Predicate)【總結】

函式式介面、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); } }