下面的demo很多奴饮,一個函數(shù)接口只需讀懂一個demo互纯,邏輯都是一樣的,以后用到了粘貼運行看結(jié)果就一目了然。
準(zhǔn)備知識
- 匿名內(nèi)部類的鏈接:http://www.reibang.com/p/80e88c0e7e30
- 函數(shù)式接口的概念+demo:http://www.reibang.com/p/1a81a1af9290
- 函數(shù)式接口的作用:Lambda表達式的操作要基于函數(shù)式接口贯城,Lambda表達式等同于該接口的實現(xiàn)類的對象,也等同該接口的匿名內(nèi)部類霹娄,可以看做是匿名內(nèi)部類的優(yōu)化能犯。函數(shù)式接口就是3者的父類。還有后面Stream流的常用的方法犬耻,其參數(shù)就是一個個函數(shù)式接口踩晶。如果說的不夠清晰,請看上面的鏈接枕磁,查看demo渡蜻。
Supplier供給型接口
- 顧名思義:只出不進
- java.util.function.Supplier<T> 接口僅包含一個無參的方法: T get() 。用來獲取一個泛型參數(shù)指定類型的對象數(shù)據(jù)。由于這是一個函數(shù)式接口茸苇,這也就意味著對應(yīng)的Lambda表達式需要“對外提供”一個符合泛型類型的對象數(shù)據(jù)排苍。
- 如果我定義了Supplier<T>中的T是一個String類型,那么其get()方法也必將返回一個String類型數(shù)據(jù)学密。
-
()
:表示get這個抽象方法名[忽略了方法名淘衙,因為函數(shù)式接口里面只有一個抽象方法,不可能是別的方法腻暮,因此可忽略不寫]+參數(shù)[此處沒有參數(shù)]彤守。 -
{return "胡歌";}
:是get這個抽象方法的具體實現(xiàn)。 - Stream流中
forEach(Supplier函數(shù)型接口)
;
/*
常用的函數(shù)式接口
java.util.function.Supplier<T>接口僅包含一個無參的方法:T get()哭靖。
用來獲取一個泛型參數(shù)指定類型的對象數(shù)據(jù)具垫。
Supplier<T>接口被稱之為生產(chǎn)型接口,指定接口的泛型是什么類型,
那么接口中的get方法就會生產(chǎn)什么類型的數(shù)據(jù)
*/
public class Demo01Supplier {
//定義一個方法,方法的參數(shù)傳遞Supplier<T>接口,
// 泛型執(zhí)行String,get方法就會返回一個String
public static String getString(Supplier<String> sup){
return sup.get();
}
public static void main(String[] args) {
//調(diào)用getString方法,方法的參數(shù)Supplier是一個函數(shù)式接口,
// 所以可以傳遞Lambda表達式
String s = getString(()->{
//生產(chǎn)一個字符串,并返回
return "胡歌";
});
System.out.println(s);
//優(yōu)化Lambda表達式
String s2 = getString(()->"胡歌");
System.out.println(s2);
}
}
/*
練習(xí):求數(shù)組元素最大值
使用Supplier接口作為方法參數(shù)類型,通過Lambda表達式求出int數(shù)組中的最大值试幽。
提示:接口的泛型請使用java.lang.Integer類做修。
*/
public class Demo02Test {
//定義一個方法,用于獲取int類型數(shù)組中元素的最大值,方法的參數(shù)傳遞Supplier接口,
// 泛型使用Integer
public static int getMax(Supplier<Integer> sup){
return sup.get();
}
public static void main(String[] args) {
//定義一個int類型的數(shù)組,并賦值
int[] arr = {100,0,-50,880,99,33,-30};
//調(diào)用getMax方法,方法的參數(shù)Supplier是一個函數(shù)式接口,所以可以傳遞Lambda表達式
int maxValue = getMax(()->{
//獲取數(shù)組的最大值,并返回
//定義一個變量,把數(shù)組中的第一個元素賦值給該變量,記錄數(shù)組中元素的最大值
int max = arr[0];
//遍歷數(shù)組,獲取數(shù)組中的其他元素
for (int i : arr) {
//使用其他的元素和最大值比較
if(i>max){
//如果i大于max,則替換max作為最大值
max = i;
}
}
//返回最大值
return max;
});
System.out.println("數(shù)組中元素的最大值是:"+maxValue);
}
}
Consumer消費型接口
顧名思義:只進不出
- java.util.function.Consumer<T> 接口則正好與Supplier接口相反,它不是生產(chǎn)一個數(shù)據(jù)抡草,而是消費一個數(shù)據(jù)饰及,其數(shù)據(jù)類型由泛型決定。接口中包含抽象方法 void accept(T t) 康震,意為消費一個指定泛型的數(shù)據(jù)燎含。
/*
java.util.function.Consumer<T>接口則正好與Supplier接口相反,
它不是生產(chǎn)一個數(shù)據(jù)腿短,而是消費一個數(shù)據(jù)屏箍,其數(shù)據(jù)類型由泛型決定。
Consumer接口中包含抽象方法void accept(T t)橘忱,意為消費一個指定泛型的數(shù)據(jù)赴魁。
Consumer接口是一個消費型接口,泛型執(zhí)行什么類型,就可以使用accept方法消費什么類型的數(shù)據(jù)
至于具體怎么消費(使用),需要自定義(輸出,計算....)
*/
public class Demo01Consumer {
/*
定義一個方法
方法的參數(shù)傳遞一個字符串的姓名
方法的參數(shù)傳遞Consumer接口,泛型使用String
可以使用Consumer接口消費字符串的姓名
*/
public static void method(String name, Consumer<String> con){
con.accept(name);
}
public static void main(String[] args) {
//調(diào)用method方法,傳遞字符串姓名,方法的另一個參數(shù)是Consumer接口,
// 是一個函數(shù)式接口,所以可以傳遞Lambda表達式
method("趙麗穎",(String name)->{
//對傳遞的字符串進行消費
//消費方式:直接輸出字符串
//System.out.println(name);
//消費方式:把字符串進行反轉(zhuǎn)輸出
String reName = new StringBuffer(name).reverse().toString();
System.out.println(reName);
});
}
}
/*
Consumer接口的默認方法andThen
作用:需要兩個Consumer接口,可以把兩個Consumer接口組合到一起,在對數(shù)據(jù)進行消費
例如:
Consumer<String> con1
Consumer<String> con2
String s = "hello";
con1.accept(s);
con2.accept(s);
連接兩個Consumer接口 再進行消費
con1.andThen(con2).accept(s); 誰寫前邊誰先消費
*/
public class Demo02AndThen {
//定義一個方法,方法的參數(shù)傳遞一個字符串和兩個Consumer接口,Consumer接口的泛型使用字符串
public static void method(String s,Consumer<String> con1,Consumer<String> con2){
//con1.accept(s);
//con2.accept(s);
//使用andThen方法,把兩個Consumer接口連接到一起,在消費數(shù)據(jù)
//con1連接con2,先執(zhí)行con1消費數(shù)據(jù),在執(zhí)行con2消費數(shù)據(jù)
con1.andThen(con2).accept(s);
}
public static void main(String[] args) {
//調(diào)用method方法,傳遞一個字符串,兩個Lambda表達式
method("Hello",
(t)->{
//消費方式:把字符串轉(zhuǎn)換為大寫輸出
System.out.println(t.toUpperCase());
},
(t)->{
//消費方式:把字符串轉(zhuǎn)換為小寫輸出
System.out.println(t.toLowerCase());
});
}
}
/*
練習(xí):
字符串?dāng)?shù)組當(dāng)中存有多條信息,請按照格式“姓名:XX钝诚。性別:XX颖御。”的格式將信息打印出來凝颇。
要求將打印姓名的動作作為第一個Consumer接口的Lambda實例潘拱,
將打印性別的動作作為第二個Consumer接口的Lambda實例,
將兩個Consumer接口按照順序“拼接”到一起拧略。
*/
public class Demo03Test {
//該方法,參數(shù)傳遞String類型的數(shù)組和兩個Consumer接口,泛型使用String
public static void printInfo(String[] arr,Consumer<String> con1,Consumer<String> con2){
//遍歷字符串?dāng)?shù)組
for (String message : arr) {
//使用andThen方法連接兩個Consumer接口,消費字符串
con1.andThen(con2).accept(message);
}
}
public static void main(String[] args) {
//定義一個字符串類型的數(shù)組
String[] arr = { "迪麗熱巴,女", "古力娜扎,女", "馬爾扎哈,男" };
//調(diào)用printInfo方法,傳遞一個字符串?dāng)?shù)組,和兩個Lambda表達式
printInfo(arr,(message)->{
//消費方式:對message進行切割,獲取姓名,按照指定的格式輸出
String name = message.split(",")[0];
System.out.print("姓名: "+name);
},(message)->{
//消費方式:對message進行切割,獲取年齡,按照指定的格式輸出
String age = message.split(",")[1];
System.out.println("芦岂。年齡: "+age+"。");
});
}
}
Predicate斷定型接口
- 顧名思義:斷定是否
- 有時候我們需要對某種類型的數(shù)據(jù)進行判斷垫蛆,從而得到一個boolean值結(jié)果禽最。這時可以使用java.util.function.Predicate<T> 接口腺怯。接口中包含一個抽象方法: boolean test(T t)
- Stream流中
filter(Predicate斷定型接口)
/*
java.util.function.Predicate<T>接口
作用:對某種數(shù)據(jù)類型的數(shù)據(jù)進行判斷,結(jié)果返回一個boolean值
Predicate接口中包含一個抽象方法:
boolean test(T t):用來對指定數(shù)據(jù)類型數(shù)據(jù)進行判斷的方法
結(jié)果:
符合條件,返回true
不符合條件,返回false
*/
public class Demo01Predicate {
/*
定義一個方法
參數(shù)傳遞一個String類型的字符串
傳遞一個Predicate接口,泛型使用String
使用Predicate中的方法test對字符串進行判斷,并把判斷的結(jié)果返回
*/
public static boolean checkString(String s, Predicate<String> pre){
return pre.test(s);
}
public static void main(String[] args) {
//定義一個字符串
String s = "abcdef";
//調(diào)用checkString方法對字符串進行校驗,參數(shù)傳遞字符串和Lambda表達式
/*boolean b = checkString(s,(String str)->{
//對參數(shù)傳遞的字符串進行判斷,判斷字符串的長度是否大于5,并把判斷的結(jié)果返回
return str.length()>5;
});*/
//優(yōu)化Lambda表達式
boolean b = checkString(s,str->str.length()>5);
System.out.println(b);
}
}
/*
邏輯表達式:可以連接多個判斷的條件
&&:與運算符,有false則false
||:或運算符,有true則true
!:非(取反)運算符,非真則假,非假則真
需求:判斷一個字符串,有兩個判斷的條件
1.判斷字符串的長度是否大于5
2.判斷字符串中是否包含a
兩個條件必須同時滿足,我們就可以使用&&運算符連接兩個條件
Predicate接口中有一個方法and,表示并且關(guān)系,也可以用于連接兩個判斷條件
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) && other.test(t);
}
方法內(nèi)部的兩個判斷條件,也是使用&&運算符連接起來的
*/
public class Demo02Predicate_and {
/*
定義一個方法,方法的參數(shù),傳遞一個字符串
傳遞兩個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";
//調(diào)用checkString方法,參數(shù)傳遞字符串和兩個Lambda表達式
boolean b = checkString(s,(String str)->{
//判斷字符串的長度是否大于5
return str.length()>5;
},(String str)->{
//判斷字符串中是否包含a
return str.contains("a");
});
System.out.println(b);
}
}
/*
需求:判斷一個字符串,有兩個判斷的條件
1.判斷字符串的長度是否大于5
2.判斷字符串中是否包含a
滿足一個條件即可,我們就可以使用||運算符連接兩個條件
Predicate接口中有一個方法or,表示或者關(guān)系,也可以用于連接兩個判斷條件
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
方法內(nèi)部的兩個判斷條件,也是使用||運算符連接起來的
*/
public class Demo03Predicate_or {
/*
定義一個方法,方法的參數(shù),傳遞一個字符串
傳遞兩個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";
//調(diào)用checkString方法,參數(shù)傳遞字符串和兩個Lambda表達式
boolean b = checkString(s,(String str)->{
//判斷字符串的長度是否大于5
return str.length()>5;
},(String str)->{
//判斷字符串中是否包含a
return str.contains("a");
});
System.out.println(b);
}
}
/*
需求:判斷一個字符串長度是否大于5
如果字符串的長度大于5,那返回false
如果字符串的長度不大于5,那么返回true
所以我們可以使用取反符號!對判斷的結(jié)果進行取反
Predicate接口中有一個方法negate,也表示取反的意思
default Predicate<T> negate() {
return (t) -> !test(t);
}
*/
public class Demo04Predicate_negate {
/*
定義一個方法,方法的參數(shù),傳遞一個字符串
使用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";
//調(diào)用checkString方法,參數(shù)傳遞字符串和Lambda表達式
boolean b = checkString(s,(String str)->{
//判斷字符串的長度是否大于5,并返回結(jié)果
return str.length()>5;
});
System.out.println(b);
}
}
/*
練習(xí):集合信息篩選
數(shù)組當(dāng)中有多條“姓名+性別”的信息如下,
String[] array = { "迪麗熱巴,女", "古力娜扎,女", "馬爾扎哈,男", "趙麗穎,女" };
請通過Predicate接口的拼裝將符合要求的字符串篩選到集合ArrayList中川无,
需要同時滿足兩個條件:
1. 必須為女生瓢喉;
2. 姓名為4個字。
分析:
1.有兩個判斷條件,所以需要使用兩個Predicate接口,對條件進行判斷
2.必須同時滿足兩個條件,所以可以使用and方法連接兩個判斷條件
*/
public class Demo05Test {
/*
定義一個方法
方法的參數(shù)傳遞一個包含人員信息的數(shù)組
傳遞兩個Predicate接口,用于對數(shù)組中的信息進行過濾
把滿足條件的信息存到ArrayList集合中并返回
*/
public static ArrayList<String> filter(String[] arr,Predicate<String> pre1,Predicate<String> pre2){
//定義一個ArrayList集合,存儲過濾之后的信息
ArrayList<String> list = new ArrayList<>();
//遍歷數(shù)組,獲取數(shù)組中的每一條信息
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) {
//定義一個儲存字符串的數(shù)組
String[] array = { "迪麗熱巴,女", "古力娜扎,女", "馬爾扎哈,男", "趙麗穎,女" };
//調(diào)用filter方法,傳遞字符串?dāng)?shù)組和兩個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);
}
}
}
Function函數(shù)型接口
*顧名思義:y=fun(x),做一個類型轉(zhuǎn)換
- java.util.function.Function<T,R> 接口用來根據(jù)一個類型的數(shù)據(jù)得到另一個類型的數(shù)據(jù)舀透,前者稱為前置條件栓票,后者稱為后置條件。
- Function 接口中最主要的抽象方法為: R apply(T t) 愕够,根據(jù)類型T的參數(shù)獲取類型R的結(jié)果走贪。
- 使用的場景例如:將 String 類型轉(zhuǎn)換為 Integer 類型。Stream 中
map(Function函數(shù)型接口)
;
/*
java.util.function.Function<T,R>接口用來根據(jù)一個類型的數(shù)據(jù)得到另一個類型的數(shù)據(jù)惑芭,
前者稱為前置條件坠狡,后者稱為后置條件。
Function接口中最主要的抽象方法為:R apply(T t)遂跟,根據(jù)類型T的參數(shù)獲取類型R的結(jié)果逃沿。
使用的場景例如:將String類型轉(zhuǎn)換為Integer類型。
*/
public class Demo01Function {
/*
定義一個方法
方法的參數(shù)傳遞一個字符串類型的整數(shù)
方法的參數(shù)傳遞一個Function接口,泛型使用<String,Integer>
使用Function接口中的方法apply,把字符串類型的整數(shù),轉(zhuǎn)換為Integer類型的整數(shù)
*/
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) {
//定義一個字符串類型的整數(shù)
String s = "1234";
//調(diào)用change方法,傳遞字符串類型的整數(shù),和Lambda表達式
change(s,(String str)->{
//把字符串類型的整數(shù),轉(zhuǎn)換為Integer類型的整數(shù)返回
return Integer.parseInt(str);
});
//優(yōu)化Lambda
change(s,str->Integer.parseInt(str));
}
}
/*
Function接口中的默認方法andThen:用來進行組合操作
需求:
把String類型的"123",轉(zhuǎn)換為Inteter類型,把轉(zhuǎn)換后的結(jié)果加10
把增加之后的Integer類型的數(shù)據(jù),轉(zhuǎn)換為String類型
分析:
轉(zhuǎn)換了兩次
第一次是把String類型轉(zhuǎn)換為了Integer類型
所以我們可以使用Function<String,Integer> fun1
Integer i = fun1.apply("123")+10;
第二次是把Integer類型轉(zhuǎn)換為String類型
所以我們可以使用Function<Integer,String> fun2
String s = fun2.apply(i);
我們可以使用andThen方法,把兩次轉(zhuǎn)換組合在一起使用
String s = fun1.andThen(fun2).apply("123");
fun1先調(diào)用apply方法,把字符串轉(zhuǎn)換為Integer
fun2再調(diào)用apply方法,把Integer轉(zhuǎn)換為字符串
*/
public class Demo02Function_andThen {
/*
定義一個方法
參數(shù)串一個字符串類型的整數(shù)
參數(shù)再傳遞兩個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) {
//定義一個字符串類型的整數(shù)
String s = "123";
//調(diào)用change方法,傳遞字符串和兩個Lambda表達式
change(s,(String str)->{
//把字符串轉(zhuǎn)換為整數(shù)+10
return Integer.parseInt(str)+10;
},(Integer i)->{
//把整數(shù)轉(zhuǎn)換為字符串
return i+"";
});
//優(yōu)化Lambda表達式
change(s,str->Integer.parseInt(str)+10,i->i+"");
}
}
/*
練習(xí):自定義函數(shù)模型拼接
題目
請使用Function進行函數(shù)模型的拼接幻锁,按照順序需要執(zhí)行的多個函數(shù)操作為:
String str = "趙麗穎,20";
分析:
1. 將字符串截取數(shù)字年齡部分凯亮,得到字符串;
Function<String,String> "趙麗穎,20"->"20"
2. 將上一步的字符串轉(zhuǎn)換成為int類型的數(shù)字哄尔;
Function<String,Integer> "20"->20
3. 將上一步的int數(shù)字累加100假消,得到結(jié)果int數(shù)字。
Function<Integer,Integer> 20->120
*/
public class Demo03Test {
/*
定義一個方法
參數(shù)傳遞包含姓名和年齡的字符串
參數(shù)再傳遞3個Function接口用于類型轉(zhuǎn)換
*/
public static int change(String s, Function<String,String> fun1,
Function<String,Integer> fun2,Function<Integer,Integer> fun3){
//使用andThen方法把三個轉(zhuǎn)換組合到一起
return fun1.andThen(fun2).andThen(fun3).apply(s);
}
public static void main(String[] args) {
//定義一個字符串
String str = "趙麗穎,20";
//調(diào)用change方法,參數(shù)傳遞字符串和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);
}
}