一、有且只有一個抽象方法的接口java
二、函數式接口,即適用於函數式編程場景的接口。
Java中的函數式編程體現就是Lambda,因此函數式接口就是能夠適用於Lambda使用的接口。
只有確保接口中有且僅有一個抽象方法,Java中的Lambda才能順利地進行推導。編程
public interface InterfaceName { public abstract 返回值類型 方法名稱(可選參數信息); // 其餘非抽象方法內容 } public interface MyFunctionalInterface { void myMethod(); }
@FunctionalInterface public interface MyFunctionalInterface { void myMethod(); }
一旦使用該註解來定義接口,編譯器將會強制檢查該接口是否確實有且僅有一個抽象方法,不然將會報錯。
須要注意的是,即便不使用該註解,只要知足函數式接口的定義,這仍然是一個函數式接口,使用起來都同樣。數組
Supplier
、Consumer
、Predicate
、Function
app
@FunctionalInterface public interface Supplier<T> { T get(); }
/** * Supplier 供給型接口 沒有參數,只有返回值 */ public class Demo04 { public static void main(String[] args) { // Supplier supplier = new Supplier<Integer>() { // @Override // public Integer get() { // System.out.println("get()"); // return 1024; // } // }; Supplier supplier = ()->{ return 1024; }; System.out.println(supplier.get()); } }
抽象方法:getide
/** * 經常使用的函數式接口 * java.util.function.Supplier<T>接口僅包含一個無參的方法:T get()。 * 用來獲取一個泛型參數指定類型的對象數據。 * * Supplier<T>接口被稱之爲生產型接口,指定接口的泛型是什麼類型 * 那麼接口中的get方法就會生產什麼類型的數據 */ public class SupplierDemo01 { //定義一個方法,方法的參數傳遞Supplier<T>接口,泛型執行String,get方法就會返回一個String public static String getString(Supplier<String> sup){ return sup.get(); } public static void main(String[] args) { String string = getString(() -> { return "胡歌"; }); System.out.println(string); //優化Lambda表達式 String s2 = getString(()->"胡歌"); System.out.println(s2); } } /** * 練習:求數組元素最大值 * 使用Supplier接口做爲方法參數類型,經過Lambda表達式求出int數組中的最大值。 * 提示:接口的泛型請使用java.lang.Integer類。 */ public class TestDemo02 { public static int getMax(Supplier<Integer> supplier){ return supplier.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) max = i; //若是i大於max,則替換max做爲最大值 } return max; }); System.out.println(maxValue); } }
消費性接口函數式編程
@FunctionalInterface // 只有輸入,沒有返回值 public interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
/** * Consumer 消費型接口: 只有輸入,沒有返回值 */ public class Demo03 { public static void main(String[] args) { // Consumer<String> consumer = new Consumer<String>() { // @Override // public void accept(String str) { // System.out.println(str); // } // }; Consumer<String> consumer = (str)->{System.out.println(str);}; consumer.accept("sdadasd"); } }
抽象方法:accept函數
消費一個指定泛型的數據優化
/** * java.util.function.Consumer<T>接口則正好與Supplier接口相反, * 它不是生產一個數據,而是消費一個數據,其數據類型由泛型決定。 * Consumer接口中包含抽象方法void accept(T t),意爲消費一個指定泛型的數據。 * * Consumer接口是一個消費型接口,泛型執行什麼類型,就可使用accept方法消費什麼類型的數據 * 至於具體怎麼消費(使用),須要自定義(輸出,計算....) */ public class ConsumerDemo01 { public static void method(String name, Consumer<String> consumer){ consumer.accept(name); } public static void main(String[] args) { //Consumer<String> consumer = (str)->{System.out.println(str);}; //consumer.accept("sdadasd"); //accept中的name值"趙麗穎"賦值給了下面的name method("趙麗穎",(String name)->{ //對傳遞的字符串進行消費 //消費方式:直接輸出字符串 System.out.println(name); //消費方式:把字符串進行反轉輸出 String reName = new StringBuffer(name).reverse().toString(); System.out.println(reName); }); } }
默認方法:andThenui
"一步接一步」操做spa
/** * Consumer接口的默認方法andThen * 做用:須要兩個Consumer接口,能夠把兩個Consumer接口組合到一塊兒,在對數據進行消費 * * 例如: * Consumer<String> con1 * Consumer<String> con2 * String s = "hello"; * con1.accept(s); * con2.accept(s); * 鏈接兩個Consumer接口 再進行消費 * con1.andThen(con2).accept(s); 誰寫前邊誰先消費 */ public class ConsumerAndThenDemo02 { //定義一個方法,方法的參數傳遞一個字符串和兩個Consumer接口,Consumer接口的泛型使用字符串 public static void method(String s, Consumer<String> con1,Consumer<String> con2){ //con1.accept(s); //con2.accept(s); //使用andThen方法,把兩個Consumer接口鏈接到一塊兒,在消費數據 //con1鏈接con2,先執行con1消費數據,在執行con2消費數據 con1.andThen(con2).accept(s); } public static void main(String[] args) { method("Hello",(t)->{ System.out.println(t.toUpperCase()); },(t)->{ System.out.println(t.toLowerCase()); }); } }
斷言型接口:有一個輸入參數,返回值只能是布爾值
@FunctionalInterface public interface Predicate<T> { boolean test(T t); 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); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
/** * 判定型接口:有一個輸入參數,返回值只能是 布爾值! */ public class Demo02 { public static void main(String[] args) { //判斷字符串是否爲空 // Predicate<String> predicate = new Predicate<String>(){ // @Override // public boolean test(String str) { // return str.isEmpty(); // } // }; Predicate<String> predicate = (str)->{return str.isEmpty(); }; System.out.println(predicate.test("")); } }
抽象方法:test
用於條件判斷的場景
/** * java.util.function.Predicate<T>接口 * 做用:對某種數據類型的數據進行判斷,結果返回一個boolean值 * * Predicate接口中包含一個抽象方法: * boolean test(T t):用來對指定數據類型數據進行判斷的方法 * 結果: * 符合條件,返回true * 不符合條件,返回false */ public class PredicateDemo01 { /* 定義一個方法 參數傳遞一個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
邏輯並。兩個條件同時知足返回true
/** * 需求:判斷一個字符串,有兩個判斷的條件 * 1.判斷字符串的長度是否大於5 * 2.判斷字符串中是否包含a * 兩個條件必須同時知足,咱們就可使用&&運算符鏈接兩個條件 */ public class PredicateAndDemo02 { 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); } 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
邏輯或,兩個條件知足一個返回true
/** * 需求:判斷一個字符串,有兩個判斷的條件 * 1.判斷字符串的長度是否大於5 * 2.判斷字符串中是否包含a * 知足一個條件便可,咱們就可使用||運算符鏈接兩個條件 * */ public class PredicateOrDemo03 { /* 定義一個方法,方法的參數,傳遞一個字符串 傳遞兩個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("b"); }); System.out.println(b); } }
默認方法:negate
結果取反
/** * 需求:判斷一個字符串長度是否大於5 * 若是字符串的長度大於5,那返回false * 若是字符串的長度不大於5,那麼返回true * 因此咱們可使用取反符號!對判斷的結果進行取反 */ public class PredicateNegateDemo04 { /** * 定義一個方法,方法的參數,傳遞一個字符串 * 使用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); } }
@FunctionalInterface // T 傳入參數、R返回類型 public interface Function<T, R> { R apply(T t); default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } static <T> Function<T, T> identity() { return t -> t; } }
/** * Function 函數型接口, 有一個輸入參數,有一個輸出 * 只要是 函數型接口 能夠 用 lambda表達式簡化 */ public class Demo01 { public static void main(String[] args) { // Function<String,String> function = new Function<String,String>() { // @Override // public String apply(String str) { // return str; // } // }; Function<String,String> function = (str)->{return str;}; System.out.println(function.apply("asd")); } }
/** * java.util.function.Function<T,R>接口用來根據一個類型的數據獲得另外一個類型的數據, * 前者稱爲前置條件,後者稱爲後置條件。 * Function接口中最主要的抽象方法爲:R apply(T t),根據類型T的參數獲取類型R的結果。 * 使用的場景例如:將String類型轉換爲Integer類型。 */ public class FunctionDemo01 { /** * 定義一個方法 * 方法的參數傳遞一個字符串類型的整數 * 方法的參數傳遞一個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接口中的默認方法andThen:用來進行組合操做 * * 需求: * 把String類型的"123",轉換爲Inteter類型,把轉換後的結果加10 * 把增長以後的Integer類型的數據,轉換爲String類型 * * 分析: * 轉換了兩次 * 第一次是把String類型轉換爲了Integer類型 * 因此咱們可使用Function<String,Integer> fun1 * Integer i = fun1.apply("123")+10; * 第二次是把Integer類型轉換爲String類型 * 因此咱們可使用Function<Integer,String> fun2 * String s = fun2.apply(i); * 咱們可使用andThen方法,把兩次轉換組合在一塊兒使用 * String s = fun1.andThen(fun2).apply("123"); * fun1先調用apply方法,把字符串轉換爲Integer * fun2再調用apply方法,把Integer轉換爲字符串 */ public class FunctionAndThenDemo02 { /** * 定義一個方法 * 參數串一個字符串類型的整數 * 參數再傳遞兩個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+""); } }