JAVA8函數式接口使用

概念

函數式接口在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

主要語法:

  1.  () -> 代表了 lambda的一個表達式
  2.  單行代碼無需寫return (無論函數式接口有沒有返回值),花括號
  3.  多行代碼必須寫花括號,有返回值的一定要寫返回值
  4.  單行代碼且有參數的情況下可以不寫 ()   如  s->System.out.println(s)
  5.  (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
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章