23.Java語言函數式接口和方法引用

函數式接口

函數式接口:

有且僅有一個抽象方法的接口(可以有其他方法)

@FunctionalInterface註解:

和Override用法基本相同,此註解可以用於任何接口,表示函數式接口,加了註解編譯器會自動檢是否有且僅有一個抽象函數。不加註解滿足函數式接口的條件也是函數式接口

自定義函數式接口:

@FunctionalInterface
interface IB {
    int sub(int a,int b);
}

public class 有參有返回值 {
    public static void main(String[] args) {
        fun(new IB() {
            @Override
            public int sub(int a,int b) {
                System.out.println("有參有返回值-匿名內部類");
                return a + b;
            }
        },10,20);
        fun((a,b)->{
            System.out.println("有參有返回值-lambda表達式");
            return a + b;
        },10,20);
    }

    public static void fun(IB ib,int x,int y) {
        System.out.println(ib.sub(x, y));
    }
}

 

函數式編程

Lambda的應用_執行延遲:

       計算完數據再去判斷是否執行和先判斷是否執行再計算數據,如果先計算就會浪費資源,

讓計算的部分先交給接口,然後判斷條件,如果滿足在進行計算。

@FunctionalInterface
interface IA {
    String s();
}

public class 執行延遲 {
    public static void main(String[] args) {
        String s1 = "我";
        String s2 = "愛";
        String s3 = "你";
        fun(2,()->s1 + s2 + s3);
    }

    public static void fun(int level,IA ia) {
        if (level == 1) {
            System.out.println(ia.s());
        }
    }
}

Lambda的應用_作爲參數和返回值:

@FunctionalInterface
interface IC{
    void show();
}

public class 作爲返回值 {
    public static void main(String[] args) {
        fun1(()-> System.out.println("作爲參數"));
        fun2().show();
    }

    //作爲參數
    public static void fun1(IC ic) {
        ic.show();
    }

    //作爲返回值
    public static IC fun2() {
        return () -> System.out.println("作爲返回值");
    }
}

 

方法引用

所謂“方法引用”就是:使用現有的方法,來代替實現的Lambda。

替代規則:

“替代的方法”的形參、返回值類型,必須與被替換的"函數式接口”中抽象

         方法的一致。

靜態方法替代Lambda:

可以是自定義靜態方法,也可以是類庫中的靜態方法,只要這個靜態方法和函數式接口中的抽象方法一樣,(參數和返回值類型一致)就可以替代,語法 ::(雙冒號)

 
@FunctionalInterface
interface IA{
    void show();
}

public class 自定義方法替代Lambda {
    public static void main(String[] args) {
        //使用Lambda表達式
        fun(()-> System.out.println("使用Lambda表達式"));

        //使用自定義方法替代Lambda表達式
        fun(自定義方法替代Lambda::s);
    }

    public static void fun(IA ia) {
        ia.show();
    }

    public static void s() {
        System.out.println("自定義靜態方法替代Lambda");
    }
}

對象成員方法替代:

       首先創建對象,替換格式 對象名::方法名。返回值類型和參數一致

使用this本類方法:

@FunctionalInterface
interface Game{
    public void run();
}

class Student{
    public void playGame(Game game) {
        System.out.println("我開始打遊戲:");
        game.run();
    }

    public void show(){
//        playGame(() -> System.out.println("我喜歡打羽毛球...."));
        playGame(this::ymq);
    }

    public void ymq(){
        System.out.println("我喜歡打羽毛球....");
    }
}

public class Demo {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.show();
    }
}

使用super父類方法:

要有繼承關係

@FunctionalInterface
interface Game{
    public void run();
}

class Fu{
    public void like(){
        System.out.println("我喜歡喝啤酒(我是父親)....");
    }
}

class Student extends Fu{
    public void playGame(Game game) {
        System.out.println("我開始打遊戲:");
        game.run();
    }

    public void show(){
        //1.使用Lambda
        playGame(() -> System.out.println("我喜歡喝啤酒...."));

        //2.使用父類的like方法代替Lambda表達式
        playGame(super::like);//使用父類的like方法代替Lambda表達式
    }
}

public class Demo {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.show();
    }
}

類的構造器引用:

      

@FunctionalInterface
interface ID {
    Cat getCat();
}

interface IE{
    Cat getCat(String name);
}

class Cat {
    public String name;
    public Cat() {
    }

    public Cat(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println("小貓吃魚");
    }

    public void pao() {
        System.out.println(name+"在跑");
    }
}

public class 類的構造器引用 {
    public static void main(String[] args) {
        //Lambda表達式
        fun(() -> new Cat());

        //類的構造器替代(無參)
        fun(Cat::new);

        //類的構造器替代(有參)
        fun2(Cat::new,"大花貓");
    }

    public static void fun(ID id) {
        id.getCat().eat();
    }

    public static void fun2(IE ie,String name) {
        ie.getCat(name).pao();
    }
}

數組構造器引用:

@FunctionalInterface
interface IA{
    public int[] getArr(int len);
}

public class Demo {
    public static void main(String[] args) {
        //2.使用Lambda
        fun((int len)->{return new int[len];},10);

        //3.使用數組的構造器代替:Lambda
        fun(int[]::new,15);
    }

    public static void fun(IA a,int len){
        int[] arr = a.getArr(len);
        System.out.println(arr.length);
    }
}

常用函數式接口;

生產者接口_Supplier接口

       1).生產者結果:只生產數據,不接收參數

public static void main(String[] args) {
    fun1(()->10);
    fun2(()->"hello");
}

public static void fun1(Supplier<Integer> ia) {
    Integer a = ia.get();
    System.out.println(a);
}

public static void fun2(Supplier<String> is) {
    String s = is.get();
    System.out.println(s);
}

 

消費者接口_Consumer接口_抽象方法accept

       1).消費接口,只接受參數,無返回值;

 public static void main(String[] args) {
    fun((String s)-> System.out.println(s),"hello");
}

public static void fun(Consumer<String> cs,String s) {
    cs.accept(s);
}

 

Consumer接口_默認方法andThen

       作用:將兩個Consumer對象的accept()方法的結果連在一起

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

}

 

例子:消費一個數據的時候,先調用第一個參數的accept,然後調用第二個參數的accept

         實現兩個組合

public static void main(String[] args) {
    fun((String s)-> System.out.println("第一個:"+s),(String s)->                 System.out.println("第二個:"+s),"hello");

}

public static void fun(Consumer<String> cs1, Consumer<String> cs2, String s) {
    cs1.andThen(cs2).accept(s);

}

 

andThen返回一個Consumer類型, 重寫的accept方法的方法體是

accept(t); after.accept(t);,先調用第一個accept再調用第二個accept,對應的就是方法調用處的第一個參數和第二個參數,也就是執行兩個Consumer對象重寫的accept方法

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