1. 程式人生 > >Java8方法引用

Java8方法引用

nds ssm obj 無法 system anim 冒號 bject 解決

內容簡介:
方法引用Demo詳解
通過5種語法使用方法引用
方法引用使用總結

  1. 在Java8中方法引用Demo詳解
    1.1 方法引用出現的背景
    在使用Lambda表達式的時候,我們實際上傳遞進去的代碼就是一種解決方案:拿什麽參數做什麽操作。
    那麽考慮一種情況:如果我們在Lambda中所指定的操作方案,已經有地方存在相同方案,那是否還有必要再寫重復邏輯呢?
    1.2 問題的引出?
   //函數式接口,用於打印字符串.
    @FunctionalInterface
    interface Print{
        public void print(String s);
    }

    //使用lambda表達式完成案例測試.
    public class PrintDemo {

        public static void main(String[] args) {
            //Lambda方式解決
            print(s -> {System.out.println(s);}, "hello");
        }

        public static void print(Print p,String s){
            p.print(s);
        }
    }
?
?
    輸出結果:
            hello

1.3 問題的發現與解決
這段代碼的問題在於,對String進行控制臺打印輸出的操作方案,明明已經有了現成的實現,那就是System.out對象中的println(String)方法。既然Lambda希望做的事情就是調用println(String)方法,那何必自己手動調用呢?
能否省去Lambda的語法格式(盡管它已經相當簡潔)呢?只要“路由”過去就好了:

//函數式接口,用於打印字符串.
    @FunctionalInterface
    interface Print{
        public void print(String s);
    }

    //使用lambda表達式完成案例測試.
    public class PrintDemo {

        public static void main(String[] args) {
            //方法引用解決方式
            //請註意其中的雙冒號“::”寫法,這被稱為“方法引用”,而雙冒號是一種“引用運算符”。
            print(System.out :: print,"world");
        }

        public static void print(Print p,String s){
            p.print(s);
        }
    }
?
?
    輸出結果:
            world

1.4 方法引用案例的總結
以上例中,System.out對象中有一個重載的println(String)方法恰好就是我們所需要的。那麽對於printString方法的函數式接口參數,對比下面兩種寫法:
Lambda表達式:s -> System.out.println(s);
方法引用:System.out::println
第一種語義是指:拿到參數之後經Lambda之手,繼而傳遞給System.out.println方法去處理。第二種等效寫法的語義是指:直接讓System.out中的println方法來取代Lambda。兩種寫法的執行效果完全一樣,而第二種方法引用的寫法復用了已有方案,更加簡潔。1.5 引用運算符

雙冒號“::”為引用運算符,而它所在的表達式被稱為方法引用。如果Lambda要表達的函數方案已經存在於某個方法的實現中,那麽則可以通過雙冒號來引用該方法作為Lambda的替代者。
2.通過5種語法使用方法引用
2.1 通過對象名引用成員方法
?

  //函數式接口
    @FunctionalInterface
    interface Printable{
        public void print(String s);
    }
?
    //已存在的類,類中有打印字符串的方法.
    class AlreadyExistPrint{

        public void PrintString(String s){
        System.out.println(s);
    }
?
?
    //測試通過對象名進行方法引用.
    public class ObjectMethodReference {

        public static void main(String[] args) {
            //通過對象名引用方法
            AlreadyExistPrint ap = new AlreadyExistPrint();
            print(ap :: PrintString,"java");
        }

        public static void print(Printable p,String s){
            p.print(s);
        }
?
    }
?
    輸出結果:
            java

2.2 通過類名引用靜態方法


  //函數式接口
    @FunctionalInterface
    interface MyMath{
        int max(int a, int b);
    }
?
    //已存在的類
    這裏使用JDK提供的Math類中的靜態方法max(int a,int b);
?
?
    //測試通過類名引用靜態方法.
    public class ClassStaticMethod {

        public static void main(String[] args) {
            //通過Math類的類名引用靜態方法max();
            int max = getMax(Math :: max, 10, 20);
            System.out.println(max);
        }

        public static int getMax(MyMath lambda ,int a,int b){
            return lambda.max(a, b);
        }
?
    }
?
    輸出結果:
            20

2.3 通過類名引用成員方法


/*
    成員方法需要依托對象才可以執行,所以當並不存在對象時,成員方法無法執行。
    如果希望成員方法的引用中僅出現類名稱而不出現對象名稱,情況則要復雜一些:
    必須為其指定一個用來執行成員方法的對象實例。
    */
?
    //在函數式接口中的參數裏加入對象實例:
    @FunctionalInterface
    interface Printable{
        public void print(AlreadyExistPrint a ,String s);
    }
?
    //已存在的類
    class AlreadyExistPrint{

        public void PrintString(String s){
            System.out.println(s);
        }
?
    }
?
    //測試通過類名引用成員方法.
    public class ClassMethod {
        public static void main(String[] args) {
            //通過類名引用成員方法;
            //lambda方式實現:
            //語義解析: 拿著對象a去調用a的print方法打印s 
            print((a,s) -> {a.PrintString(s);},new AlreadyExistPrint(),"hello");

            //簡化寫法: 方法引用 (通過類名引用成員方法)
            print(AlreadyExistPrint :: PrintString,new AlreadyExistPrint(),"hello");

        }

        public static void print(Printable p ,AlreadyExistPrint a,String s){
            p.print(a,s);
        }
?
    }
?
    輸出結果:
            hello
            hello

2.4 通過super引用成員方法


    //函數式接口
    @FunctionalInterface
    interface Eat{
        void eat(String food);
    }
?
    //已存在的類
    class Animal{
        public void eat(String food){
            System.out.println("吃:"+food);
        }
    }
?
    //Animal的子類
    class Cat extends Animal{

        @Override
        public void eat(String food) {
            //通過super引用父類的方法.
            method(super :: eat,food);
        }

        public void method(Eat e, String s){
            e.eat(s);
        }
    }
?
?
    //測試通過類名引用成員方法.
    public class SuperMethod {

        public static void main(String[] args) {
            Cat c = new Cat();
            c.eat("魚");
        }
?
    }
?
    輸出結果:
            吃魚

2.5通過this引用成員方法


    //函數式接口
    interface shopping {
        void buy(int money);
    }
?
    //已存在的類
    class Man {
        //男人將來都要買個屬於自己的房子.
        public void buyHouse(int money) {
            System.out.println("買套房子消費:"+money);
        }

        //結婚就得購物,買買買啊.
        public void marry(shopping lambda,int money) {
            lambda.buy(money);
        }

        //開心方法.男人要想開心.就得結婚
        public void beHappy() {
            //通過this引用成員方法.
            marry(this::buyHouse,1000000);
        }
    }
?
?
    //測試通過類名引用成員方法.
    public class ThisMethod {
?
        public static void main(String[] args) {
            Man man = new Man();
            man.beHappy();
        }
    }
?
?
    輸出結果:
            買套房子消費:1000000

3.方法引用使用總結
? (1) Lambda表達式:s -> System.out.println(s); (2) 方法引用:System.out::println

第一種語義是指:拿到參數之後經Lambda之手,繼而傳遞給System.out.println方法去處理。
?
第二種等效寫法的語義是指:直接讓System.out中的println方法來取代Lambda。
兩種寫法的執行效果完全一樣,而第二種方法引用的寫法復用了已有方案,更加簡潔。
?
函數式接口是Lambda的基礎,而方法引用是Lambda的孿生兄弟。

Java8方法引用