Java8 新特性 函數式接口


什么是函數式接口

  函數式接口是Java8引用的一個新特性,是一種特殊的接口:SAM類型的接口(Single Abstract Method)。但是它還是一個接口,只是有些特殊罷了。  函數式接口的出現主要是為了配合Java8的另一個新特性Lamdba表達式來使用。

  • 接口中只有一個抽象方法
  • 接口中面可以加一個注解@FunctionalInterface來檢查接口中的方法是不是只有一個抽象方法
  • 在接口里面可以加入 默認方法靜態方法
  • 函數式接口也可以繼承,但是繼承的時候,抽象方法必須一樣
  • 函數式接口重寫父類的的方法,並不會計入到自己的抽象方法中

自定義函數式接口

//加入這個注解是為了檢測接口中是否符合函數式接口的要求
@FunctionalInterface
public interface MyFunctionInterction {
    //唯一的抽象方法
    void absoluMethod();

    //重寫Object的方法
    @Override
    String toString();

    //默認方法
    default void defaultMethod() {
        System.out.println("默認方法");
    }

    //靜態方法
    static void stativMethod() {
        System.out.println("靜態方法");
    }
}

函數式接口的簡單使用

里面的默認方法可以直接使用
public class TestFunctionIntection {
    public static void main(String[] args) {
        TestFunctionIntection testFunctionIntection = 
                new TestFunctionIntection();
        testFunctionIntection.test(
                //Lamdba表達式的簡單使用
                () -> System.out.println("函數式接口里面的抽象方法"));
    }

    /**
     * 自己定義的一個方法,並使用自定義的一個消費類型的函數式接口
     * @param myFunctionInterction
     */
    public void test(MyFunctionInterction 
                             myFunctionInterction) {

        //函數式接口里面的抽象方法
        myFunctionInterction.absoluMethod();

        //默認方法
        myFunctionInterction.defaultMethod();

        //靜態方法
        MyFunctionInterction.stativMethod();
    }
}

java8里面自定義的四個核心的函數式接口

上面我自定義的一個接口,就是一個消費類型的函數式接口。其實這類接口在java.util.function里面有定義的,就是void Consumer< T >,消費類型接口,上面代碼中的test方法里面的接口其實可以換成Consumer< T >接口,也可以用,下面主要就是介紹這四個函數式接口的簡單使用。

下面是這四個核心接口的簡單使用

public class FunctionTest {
    //Consumer<T> 消費型接口
    @Test
    public void test1() {
        Consumer<String> consumer = (x) -> System.out.println(x);
        consumer.accept("消費型接口,沒有返回值!");
    }
    //輸出:消費型接口,沒有返回值!

    //供給型接口
    @Test
    public void test2() {
        Supplier<String> supplier = () -> "主要的作用就是創建對象!";
        String s = supplier.get();
        System.out.println(s);
    }
    //輸出:主要的作用就是創建對象!

    //函數型接口
    //Function<T,R> T 接收的參數,R 返回值類型
    @Test
    public void test3() {
        Function<Integer, String> function = (x) -> x + ":為String類型";
        String apply = function.apply(7);
        System.out.println(apply);
    }
    //輸出:7:為String類型    

    //斷言型接口
    @Test
    public void test4() {
        Predicate<Integer> predicate = (x) -> x > 10;
        boolean test = predicate.test(11);
        System.out.println(test);
    }
    //輸出:true
}

Consumer 的應用

//Consumer<T> 消費型接口
    @Test
    public void test1() {
        //定義一個消費型接口,只輸出輸入的內容
        Consumer<String> consumer = (x) -> System.out.println(x);
        //在輸入的內容后面加上·--加上了默認方法·
        Consumer<String> consumer2 = (x) -> System.out.println(x + "--加上了默認方法");
        //執行順序  先執行 accept 后面執行 addThen(然后) 
        consumer.andThen(consumer2).accept("消費型接口,沒有返回值!");
    }
    //輸出:消費型接口,沒有返回值                     (accept輸出的值) 
    //輸出:消費型接口,沒有返回值 !--加上了默認方法 (addThen輸出的值)

Consumer 的默認方法的源碼:

default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}

  其返回值這一句是重點,先是傳入一個Consumer接口,然后返回一個Consumer接口,說明可以用表達式鏈,然后用這個特性可以把數據進一次進行加工。
  (T t) -> { accept(t); after.accept(t); };這一句,返回的順序首先是調用抽象方法,然后再調用默認方法,說明這個默認方法只可以對數據進行再加工,不能再抽象方法前面。


Supplier 的應用

    //供給型接口,這個方法若以用在工廠方法中
    @Test
    public void test2() {
        //跟據一個字符串創建對象
        Supplier<String> supplier = () -> "主要的作用就是創建對象!";
        //獲取一個對象
        String s = supplier.get();
        //獲取兩個以象
        String s1 = supplier.get();
        //兩個對象內容一樣
        System.out.println(s.equals(s1));
        System.out.println(s);
        //用方法引用的方式創建一個對象
        Supplier<SupplierTest> testSupplier = SupplierTest::new;
        //用new的方式創建一個對象
        Supplier<SupplierTest> supplierTestSupplier = () -> new SupplierTest("張三");
        //可以通過supplierTestSupplier 來獲取一個對象,並且可以調用里面的方法
        String name = supplierTestSupplier.get().getName();
        System.out.println(name);
    }
    //輸出:true
    //輸出:主要的作用就是創建對象!
    //輸出:張三

  Supplier< T >接口類型就有一個方法簽名。T get()方法,沒有默認方法。


Function< T,R > 的應用

//默認主法addThen
//函數型接口
    //Function<T,R> T 接收的參數,R 返回值類型
    @Test
    public void test3() {
        Function<String, String> f1 = (x) -> x +"+ ";
        Function<String, String> f2 = (x) -> x + "- ";
        //addThen(然后的意思)執行順序先執行f1,並且把執行后的結果作為f2的輸入參數
        String apply = f1.andThen(f2).apply("1");
        System.out.println(apply);
    }
    //輸出:1+ -

addThen的源碼:

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    Objects.requireNonNull(before);
    return (V v) -> apply(before.apply(v));
}

源碼中最重要的一句

(V v) -> apply(before.apply(v)); 規定了執行順序

    //默認主法compose
    //函數型接口
    //Function<T,R> T 接收的參數,R 返回值類型
    @Test
    public void test3() {
        Function<String, String> f1 = (x) -> x +"+ ";
        Function<String, String> f2 = (x) -> x + "- ";
        //addThen(然后的意思)執行順序先執行f2,並且把執行后的結果作為f1的輸入參數
        String apply = f1.compose(f2).apply("1");
        System.out.println(apply);
    }
    //輸出:1- +

  三個默認方法,但是最后一個用的不多,這里也就不再介紹了。


Predicate< T > 的應用

//默主方法negate 非
//斷言型接口
    @Test
    public void test4() {
        Predicate<Integer> predicate = (x) -> x > 10;
        boolean test = predicate.negate().test(11);
        System.out.println(test);
    }
    //輸出:false
    //斷言型接口
    //默認方法 or 和 and
    @Test
    public void test4() {
        Predicate<Integer> p1 = (x) -> x > 10;
        Predicate<Integer> p2 = (x) -> x < 5;
        //默認方法 or 或
        boolean test = p1.or(p2).test(3);
        //默認方法 and 且
        boolean test2 = p1.and(p2).test(3);

        System.out.println(test);
        System.out.println(test2);
    }
    //輸出:true
    //輸出:false

函數式接口的使用

  函數式接口的的使用,大部分都是在流操作里面進行,現在可以不太理解,但是可以在學習完流操作以后,再過來看,並且跟着寫一遍。代碼光看是沒有用的。如果不寫是不知道意思的。

參考的博客:淺淺的函數式接口



細節決定成敗!
個人愚見,如有不對,懇請扶正!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM