Java函數式編程-2.Lambda表達式

1.什麼是lambda表達式?

首先看一段比較熟悉的代碼片斷,目的是爲按鈕註冊一個事件監聽器,當按鈕被點擊時輸出一個提示信息"button clicked",java

Button button = new Button();
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("button clicked");
    }
});

這段自己沒有什麼問題,可是代碼量相對有點多並且語義表達上也不夠清新。那麼什麼樣的表達纔是清晰的呢?Jdk8給我帶來了一種全新的思路,可讓咱們更加優雅的實現上述功能,咱們看下述Lambda代碼。express

Button button = new Button();
 button.addActionListener(e-> System.out.println("button clicked"));

2.lambda 表達式3種表現形式

  無參數表達式: () -> System.out.println(「hello world!」)
  單個參數表達式 :  (String  sayHello) -> System.out.println(sayHello)
  多個參數表達式:   (int x, int y) -> x + y

  須要注意的是以上三種基本形式能夠根據「是否有顯示聲明參數類型」、「是否有返回值」、「是否省略()」等又會衍生出若干變化。數組

3.lambda表達式值引用

   lambda表達式操做的是對象的引用值而不是對象自己,怎麼理解呢?匿名內部類若是引用所在方法中變量那麼該變量必須聲明爲final類型,也就是對象只能對賦值一次。相似的lambda表達式引用所在方法中的變量也必須是final類型,表現形式上能夠顯示聲明final 也能夠不顯示聲明,可是該變量必須是一個既成事實上的final變量。ide

public static void sayHello(String name) {
        if (Objects.isNull(name)) {
            name = "kity";
        }
        ActionListener act = event -> System.out.println("hello " + name);
        ....
    }

上述代碼變異會提示 Variable used in lambda expression should be final or effectively final。函數

4.lambda表達式方法引用

之前咱們關注更多的是對象引用,jdk8以後新增了方法引用,須要使用關鍵字 「::」,這是jdk8咱們須要重點關注的。一下咱們詳細列舉6種方法引用的詳細格式。this

  • 靜態方法引用

格式   類名::靜態方法名spa

    注意事項:
    被引用方法參數列表和函數式接口中方法的參數一致
    接口的抽象方法沒有返回值,引用的方法能夠有返回值也能夠沒有
    接口的抽象方法有返回值,引用方法必須有同類型的返回值code

interface Transfer {
        int run(String string);
    }

    public static void main(String[] args) {
        printStr("1", Integer::valueOf);
    }

    public static void printStr(String str, Transfer t) {
        int num = t.run(str);
        System.out.println(num);
    }
  • 對象方法引用

格式   對象::方法名orm

@FunctionalInterface
    interface Action {
        String run(Integer num);
    }

    public static void main(String[] args) {
        Action t2 = new Person()::walking;
        System.out.println(t2.run(5));
    }
    class Person {
        public String walking(Integer num) {
            return "go ".concat(String.valueOf(num)).concat(" step ...");
        }
    }
  • 構造方法引用

格式   類名::new對象

interface Action {
        Person init(String string);
    }

    class Person {
        String name;

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

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }

    public static void main(String[] args) {
        Action t2 = Person::new;
        Person p2 = t2.init("李四");
        System.out.println(p2);
    }
  • 數組構造方法引用

格式   數據類型[]::new

interface Action {
        String[] run(int len);
    }

    public static void main(String[] args) {
        Action action = String[]::new;
        String[] arr = action.run(5);
        System.out.println(arr.length);
    }
  • 特定類型的方法引用

格式   類名::非靜態方法

ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "C", "B", "d");
    Collections.sort(list, String::compareToIgnoreCase);
    System.out.println(list);
  • 類中方法調用父類或本類方法引用

格式   this::方法名
          super::方法名

interface Action {
    void init();
}

class Father {
    public void buy() {
        System.out.println("買東西");
    }
}

class Son extends Father {
    public void buy() {
        System.out.println("買糖");
    }

    public void run() {
        Action action1 = this::buy;
        action1.init();
        Action action2 = super::buy;
        action2.init();
    }
}

public static void main(String[] args) {
        Son s = new Son();
        s.run();
    }

5.lambda函數接口

函數式接口是 Java8 引入的一個新特性,是一種特殊的接口:SAM類型的接口(Single Abstract Method),但本質上仍是接口。相比較於其餘接口,函數式接口有且只能有一個抽象方法。只要接口中出現多個抽象方法,那麼就不能稱之爲函數式接口,運行的時候就會報錯。爲此 Java8 提供了一個新的註解@FunctionalInterface,若是接口被這個註解標註,就說明該接口是函數式接口,若是有多於一個的抽象方法,在編譯的時候就會報錯。可是這個註解不是必需的,只要接口符合函數式接口的定義,那麼這個接口就是函數式接。

Java中主要的函數接口

               接口                              參數                                     返回類型                                         描述                      
Predicate<T>                 T               boolean 斷言型接口
Consumer<T>                 T                void 消費型接口
Function<T,R>                 T                  R 功能型接口
Supplier<T>              None                 T 供給型接口
UnaryOperator<T>               T                 T 一元運算
BinaryOperator<T>           (T,T)                 T 二元運算

6.lambda函數類型推斷

Lamda表達式是函數式接口的一個實例,然而咱們並無從Lambda表達式中看到有關函數式接口的任何信息,於是有必要弄清楚Lambda的類型是什麼?它實現了哪一個函數式接口?其實Lambda表達式的類型是從上下文推斷出來的,這裏的上下文包括以下3種: 賦值上下文 方法調用上下文(參數與返回值) 類型轉換上下文 經過這3種上下文就能夠推斷出Lambda表達式的目標類型(與之對應的函數式接口)。

相關文章
相關標籤/搜索