1. 程式人生 > >初識Lambda表示式3----JDK提供函式式介面的引出2---java

初識Lambda表示式3----JDK提供函式式介面的引出2---java

寫在前面的話

    總感覺上篇部落格有些東西需要補充,於是思來想去寫下了本篇部落格…

1.場景引入

    場景: 假如有這樣一種場景,我們的專案裡有好多方法,這些方法的引數都包含一個介面,這些介面雖然其功能各不相同,但是卻都有一個共同點,就是它們輸入引數的個數和型別相同,返回結果的型別也相同.那具體開發中該如何去處理這種情況呢???

    解決方式1: 很容易想到的一種解決方式就是我們先去定義這樣一個個的介面,再定義一個個的類去實現這些介面,然後將這些實現了指定介面的類作為引數傳遞給方法(多型),再去解決具體的問題.--------或者定義完介面後,不再去定義具體的類,而直接使用匿名內部類的方式,將所需要的介面引數傳遞給方法.這兩種解決辦法都可以算作比較傳統的方法,而且可以做到見名之義

,但是有一個比較大的缺點,就是需要寫的程式碼太多,比較複雜. 栗子如下:

package com.nrsc.lambda.FunctionInterfaceDemo;

//兩個數相加的介面
interface TwoNumberPlus {
    int plus(int x, int y);
}

//兩個數相減的介面
interface TwoNumberMinus {
    int minus(int x, int y);
}

class TwoNumberCalculateClass {
    private int x;
    private int y;

    public
TwoNumberCalculateClass(int x, int y) { this.x = x; this.y = y; } //兩個數相加 public int twoNumberPlus(TwoNumberPlus twoNumberPlus) { return twoNumberPlus.plus(this.x, this.y); } //兩個數相減 public int twoNumberMinus(TwoNumberMinus twoNumberMinus) { return
twoNumberMinus.minus(this.x, this.y); } } public class Demo1 { public static void main(String[] args) { TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8); //兩數相加 int res_plus = twoNumberCalculateClass.twoNumberPlus(new TwoNumberPlus() { @Override public int plus(int x, int y) { return x + y; } }); System.out.println(res_plus); //15 //兩數相減 int res_minus = twoNumberCalculateClass.twoNumberMinus(new TwoNumberMinus() { @Override public int minus(int x, int y) { return x - y; } }); System.out.println(res_minus); //-1 } }

    解決方式2.1: 當然還有一個看起來比較取巧的方法,那就是我們定義一個比較通用的介面,然後使用匿名內部類的方式,去完成我們的任務.栗子如下:

package com.nrsc.lambda.FunctionInterfaceDemo.demo1;

//兩個數之間進行計算的通用介面
interface TwoNumberCalculateInterface {
    int calculate(int x, int y);
}

class TwoNumberCalculateClass {
    private int x;
    private int y;

    public TwoNumberCalculateClass(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //兩個數進行計算
    public int twoNumberCalculate(TwoNumberCalculateInterface twoNumberCalculate) {
        return twoNumberCalculate.calculate(this.x, this.y);
    }

}

public class Demo1 {
    public static void main(String[] args) {
        TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8);

        //兩數相加
        int res_plus = twoNumberCalculateClass.twoNumberCalculate(new TwoNumberCalculateInterface() {
            @Override
            public int calculate(int x, int y) {
                return x + y;
            }
        });
        System.out.println(res_plus); //15

        //兩數相減
        int res_minus = twoNumberCalculateClass.twoNumberCalculate(new TwoNumberCalculateInterface() {
            @Override
            public int calculate(int x, int y) {
                return x - y;
            }
        });
        System.out.println(res_minus);  //-1
    }
}

    從上面的兩個栗子來看,方式2.1中的通用介面方式是可行的,但是在jdk8出來之前,應該很少有人會去這麼去做,為什麼呢?我想最主要的原因應該是,第二種方式其實並沒有比第一中方式省下來多少行程式碼(主要的程式碼量都在方法的重寫上),而且這樣還會讓程式碼做不到見名之義的效果.

比較有意思的一個地方

    JDK8出來以後,我們發現2.1中所提到的這種通用介面卻直接成了JDK原始碼,而且還一下整出了40個(java.util.function包內的函式式介面). 我想這肯定與lambda表示式的簡潔,以及它真正關心的只是輸入引數和返回結果的特性相關(歸納一句就是可以使匿名內部類的方式更加簡潔). 舉個栗子:

package com.nrsc.lambda.FunctionInterfaceDemo;

import java.util.function.BinaryOperator;


class TwoNumberCalculateClass {
    private int x;
    private int y;

    public TwoNumberCalculateClass(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //使用JDK自帶的函式式介面
    public int twoNumberCalculate1(BinaryOperator<Integer> binaryOperator) {
        return binaryOperator.apply(this.x, this.y);
    }
}

public class Demo1 {
    public static void main(String[] args) {
        TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8);

        /**
         * 使用JDK自帶的函式式介面以及lambda表示式
         */
        int res1 = twoNumberCalculateClass.twoNumberCalculate1((x, y) -> x + y);
        System.out.println(res1);  //15

        /**
         *  當然也可以使用原來的匿名內部類的方式----使用JDK自帶的函式式介面以及匿名內部類
         */
        int res2 = twoNumberCalculateClass.twoNumberCalculate1(new BinaryOperator<Integer>() {
            @Override
            public Integer apply(Integer integer, Integer integer2) {
                return integer + integer2;
            }
        });

        System.out.println(res2);


    }
}

    但是僅僅如此嗎?肯定不是!!!使用JDK自帶的函式式介面+lambda表示式雖然可以讓匿名內部類的方式大為簡化,但仍然會讓人感覺程式碼寫的不是那麼見名之義, 所以 JDK提供的函式式介面的出現肯定還有其他比較重要的作用 -----比如下篇部落格將會介紹到的方法引用.

    接下來將介紹一下部分JDK提供的函式式介面的簡單使用方式,其實這些介面用起來都很簡單,大家嘗試著多寫寫應該就可以掌握,我做的幾個小栗子程式碼如下:

package com.nrsc.lambda.FunctionInterfaceDemo;

import java.text.DecimalFormat;
import java.util.function.*;

/**
 * 部分JDK提供的函式式介面使用樣例
 */
public class Demo2 {
    public static void main(String[] args) {

        //斷言函式介面--- 接受一個引數,返回一個布林型別的結果
        Predicate<Integer> fun1 = i -> i > 5;
        System.out.println(fun1.test(4));

        //JDK還提供了一些帶型別的函式式介面,用這些介面我們就不必再指定泛型了,如下:
        IntPredicate fun11 = i -> i==10;
        System.out.println(fun11.test(10));

        //消費者----接受一個輸入引數並且無返回結果
        Consumer fun2 = s -> System.out.println(s + " world");
        fun2.accept("hello");

        //提供者---無需輸入引數, 為我們提供或返回一個引數
        Supplier<String> fun3 = () -> "hi , beijing";
        System.out.println(fun3.get());

        //Function<T,R>---輸入引數型別為T,返回型別為R的函式
        Function<Integer, String> fun4 = i -> new DecimalFormat("#,###").format(i);

        //一元函式-----接受一個引數為型別T,返回值型別也為T。
        UnaryOperator<String> fun5 = s -> s.replace(",", "||");
        System.out.println(fun5.apply("嘿嘿,哈哈"));

        //BiFunction<T ,U ,R> 2個輸入的函式-----輸入型別為T和U,返回型別為R的函式
        BiFunction<Integer, String, Boolean> fun6 = (i, s) -> (i + s).equals("111 hello world");
        System.out.println(fun6.apply(111, " hello world"));

        //BinaryOperator<T> 二元函式----需要輸入兩個引數,引數型別都為T,返回型別也為T的函式
        BinaryOperator<Integer> fun7 = (s, t) -> s * t;
        System.out.println(fun7.apply(7, 8));
    }
}