函式式介面、Lambda表示式(Consumer、Supplier、Function、Predicate)【總結】
阿新 • • 發佈:2019-02-01
一、函式式介面
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);
}
}