概念
函數式接口在java中是指:有且僅有一個抽象方法的接口
函數式接口,即適用於函數式編程場景的接口。而java中的函數式編程體現就是Lambda,所以函數式接口就是可以適用於Lambda使用的接口。只有確保接口中有且僅有一個抽象方法,Java中的Lambda才能順利地進行推導。
備註:“語法糖"是指使用更加方便,但是原理不變的代碼語法。例如在遍歷集合時使用的for-each語法,其實底層的實現原理仍然是迭代器,這便是“語法糖”。從應用層面來講,Java中的Lambda可以被當做是匿名內部類的“語法糖”,但是二者在原理上是不同的。
格式
接口中只存在一個抽象方法,@FunctionalInterface 註解加不加都可以。
一旦使用該註解來定義接口,編譯器將會強制檢查該接口是否確實有且僅有一個抽象方法,否則將會報錯。需要注意的是,即使不使用該註解,只要滿足函數式接口的定義,這仍然是一個函數式接口,使用起來都一樣。(該接口是一個標記接口)
修飾符 interface 接口名稱{
public abstract 返回值 方法名稱(參數列表)
// 其他方式
}
// public abstract 可以不寫 編譯器自動加上
修飾符 interface 接口名稱{
返回值 方法名稱(參數列表)
// 其他方式
}
@FunctionalInterface // 標明爲函數式接口
public abstract MyFunctionInterface{
void mrthod(); //抽象方法
}
調用自定義函數接口
public class Test_Functional {
// 定義一個含有函數式接口的方法
public static void doSomthing(MyFunctionalInterface functionalInterface) {
functionalInterface.mehod();//調用自定義函數式接口的方法
}
public static void main(String[] args) {
//調用函數式接口的方法
doSomthing(()->System.out.println("excuter lambda!"));
}
}
常用函數式接口
- Supplier 你要作爲一個供應者,自己生產數據
- Consumer 你要作爲一個消費者,利用已經準備數據
- Function 輸入一個或者兩個不同或者相同的值轉爲另一個值
- Predicate 輸入一個或者兩個不同或者相同的值總是輸出boolean
主要語法:
- () -> 代表了 lambda的一個表達式
- 單行代碼無需寫return (無論函數式接口有沒有返回值),花括號
- 多行代碼必須寫花括號,有返回值的一定要寫返回值
- 單行代碼且有參數的情況下可以不寫 () 如 s->System.out.println(s)
- (T t)中的參數類型可寫可不寫
Supplier接口(供應接口)
java.util.function.Supplier<T> 接口僅包含一個無參的方法: T get() 。用來獲取一個泛型參數指定類型的對象數據。由於這是一個函數式接口,這也就意味着對應的Lambda表達式需要“對外提供”一個符合泛型類型的對象數據。
public class Test_Supplier {
private static String test_Supplier(Supplier<String> suply) {
return suply.get(); //供應者接口
}
public static void main(String[] args) {
// 產生的數據作爲 sout 作爲輸出
System.out.println(test_Supplier(()->"產生數據"));
System.out.println(String.valueOf(new Supplier<String>() {
@Override
public String get() {
return "產生數據";
}
}));
}
}
Consumer接口
java.util.function.Consumer<T> 接口則正好與Supplier接口相反,它不是生產一個數據,而是消費一個數據,其數據類型由泛型決定。
Consumer 接口中包含抽象方法 void accept(T t) ,意爲消費一個指定泛型的數據。基本使用如:
public class Test_Consumer {
public static void generateX(Consumer<String> consumer) {
consumer.accept("hello consumer");
}
public static void main(String[] args) {
generateX(s->System.out.println(s));
}
}
默認方法:andThen:消費數據的時候,首先做一個操作,然後再做一個操作,實現組合
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) ‐> { accept(t); after.accept(t); };
//1: 返回值爲Consumer 那麼需要 ()-> 表示函數式接口
//2: accept(t);爲生產一個數據供應給 (T t)中的t
//3: after.accept(t);爲利用這個t再次生成新的函數式接口 實現類始於builder的設計模式
}
public class Test_Consumer {
private static void append(Consumer<Integer> con1, Consumer<Integer> con2) {
con1.andThen(con2).accept(1);
}
public static void main(String[] args) {
append((i) -> System.out.println(i + 1), (i) -> System.out.println(i + 2));
}
}
Predicate接口
有時候我們需要對某種類型的數據進行判斷,從而得到一個boolean值結果。這時可以使用java.util.function.Predicate<T> 接口
抽象方法:test
Predicate 接口中包含一個抽象方法: boolean test(T t) 。用於條件判斷的場景:
默認方法:and or nagte (取反)
既然是條件判斷,就會存在與、或、非三種常見的邏輯關係。
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
public class Use_Predicate {
// 判斷字符串是否存在o 即使生產者 又是消費者接口
private static void method_test(Predicate<String> predicate) {
boolean b = predicate.test("OOM SOF");
System.out.println(b);
}
// 判斷字符串是否同時存在o h 同時
private static void method_and(Predicate<String> predicate1,Predicate<String> predicate2) {
boolean b = predicate1.and(predicate2).test("OOM SOF");
System.out.println(b);
}
//判斷字符串是否一方存在o h
private static void method_or(Predicate<String> predicate1,Predicate<String> predicate2) {
boolean b = predicate1.or(predicate2).test("OOM SOF");
System.out.println(b);
}
// 判斷字符串不存在o 爲真 相反結果
private static void method_negate(Predicate<String> predicate) {
boolean b = predicate.negate().test("OOM SOF");
System.out.println(b);
}
public static void main(String[] args) {
method_test((s)->s.contains("O"));
method_and(s->s.contains("O"), s->s.contains("h"));
method_or(s->s.contains("O"), s->s.contains("h"));
method_negate(s->s.contains("O"));
}
}
Function接口
java.util.function.Function<T,R> 接口用來根據一個類型的數據得到另一個類型的數據,前者稱爲前置條件,後者稱爲後置條件
// 將數字轉換爲String類型
private static void numberToString(Function<Number, String> function) {
String apply = function.apply(12);
System.out.println("轉換結果:"+apply);
}
public static void main(String[] args) {
numberToString((s)->String.valueOf(s));
}
Function 接口中有一個默認的 andThen compose方法,用來進行組合操作。JDK源代碼如:
//兩個方法的差別在於執行順序的不同
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
// 靜態方法
private static void method_andThen(Function<Integer, Integer> f1,Function<Integer, Integer> f2) {
Integer apply = f1.andThen(f2).apply(2);
System.out.println(apply);
}
private static void method_compose(Function<Integer, Integer> f1,Function<Integer, Integer> f2) {
Integer apply = f1.compose(f2).apply(2);
System.out.println(apply);
}
public static void main(String[] args) {
numberToString((s)->String.valueOf(s));
method_andThen(s->s+1, s->s=s*2);//6
method_compose(s->s+1, s->s=s*s);//5
}