Java8之lambda表達式


簡介

Lambda 表達式是 Java 1.8 跟 Stream 機制一同推出的。Lambda 表達式極大地減少了代碼量,增加了代碼的可讀性。
引入 Lambda 表達式之后,Java 開始支持把函數作為參數傳遞

前置條件

使用 Lambda 表達式的前置條件,作為參數的接口必須是函數式接口

  1. 首先類型必須是接口 interface,不能是類 class。比如,抽象類就不可以。
  2. 函數式接口有且僅有一個未被覆寫的抽象方法

舉例:

  • Object 中方法不算
// MyRunnable 仍然算是一個“函數式接口”
public interface MyRunnable extends Runnable {
    String toString();
    boolean equals(Object obj);
    int hashCode();
}
  • 接口中的 default 方法不算
// MyRunnable2 仍然算是一個“函數式接口”
public interface MyRunnable2 extends Runnable {
    default void run2() {}
}

FunctionalInterface 注解

@FunctionalInterface 可以幫助我們在編譯期識別出一個接口是否是“函數式接口”:

Not Functional Interface

參數的傳遞

假如我們有一個如下含義的“函數式接口”:

@FunctionalInterface
public interface Formatter {
    void format(String name, int age);
}

我們可以構造一個測試:

public class LambdaTest {

    public static void main(String[] args) {
        print((String name, int age)-> System.out.println(String.format("name:%s age:%d", name, age)), "ziyu", 18);
    }

    public static void print(Formatter formatter, String name, int age) {
        formatter.format(name, age);
    }
}

多個參數

當有多個參數時,可以選擇省略所有參數類型聲明:
lambda-params
注意:
不能省略一部分保留一部分。(String name, age) -> System.out.println(name); 這是不合法的!

單個參數

lambda-param
當只有一個參數時,除了可以省略參數類型,還可以進一步省略掉括號。

編寫方式

沒有返回值

Runnable 就是一個常用的“函數式接口”,它的抽象方法 run() “沒有返回值”, 剛好適合用於此處的演示。測試例子如下:

public class LambdaTest2 {
    public static void main(String[] args) {
        runIt(()->{
            System.out.println("123");
        });
    }

    static void runIt(Runnable runnable) {
        new Thread(runnable).start();
    }
}

return-void

  • 如果寫成多行表達式,那么需要 {} 來表示代碼塊,且每一行代碼結束時需要書寫 ; 表示語句的結束。
  • 如果代碼塊中只有一條語句,那么可以通過省略 {}; 來簡寫為單行表達式

有返回值

我們定義一個 IdFactory 接口來做演示:

public interface IdFactory {
    String generateId();
}

我們的示例代碼如下:

import java.util.UUID;

public class LambdaTest3 {

    public static void main(String[] args) {
        String name = getId(()-> UUID.randomUUID() + "");
        System.out.println(name);
    }

    static String getId(IdFactory factory) {
        return factory.generateId();
    }

}

return-string

  • 如果寫成多行表達式,除了需要 {} 來表示代碼塊,和每一行代碼結束時需要書寫 ; 表示語句的結束以外,還應該在需要返回值的方法用 return 來返回值。
  • 如果代碼塊中只有一條語句,那么可以通過省略 {}; 以及 return 來簡寫為單行表達式

方法引用

比如我們要寫一段代碼,用來打印出完整的加法表達式 a + b = c,並且要求根據 a 和 b 求出 c 作為函數返回值。
首先我們定一個“計算器”接口:

public interface Calculator {
    int compute(int a, int b);
}

接着我們寫一個測試用例:

public class LambdaTest3 {

    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        // 這里不能用 (a, b), 那樣的話會產生歧義,使得編譯器報錯
        runIt((x, y)->{
            System.out.print(x);
            System.out.print(" + ");
            System.out.print(y);
            System.out.print(" = ");
            System.out.println(x + y);
            return x + y;
        }, a, b);
    }

    static void runIt(Calculator calculator, int a, int b) {
        calculator.compute(a, b);
    }
}

靜態方法引用

static-method-reference

  • 在 LambdaTest2 中定一個靜態方法 sum
  • 使用靜態方法引用 LambdaTest2::sum
  • 這樣在運行靜態方法 runIt 中的第一行 calculator.compute(a, b) 時,ab 會通過靜態方法引用傳遞給靜態方法 sum

通過這種方式,即簡化了參數的傳遞,也把“多行表達式”簡化為了“單行表達式”

成員方法引用

member-method-reference

  • new LambdaTest2()::sum: 先新建對象 LambdaTest2,並且通過該對象來使用成員變量引用
    小貼士:
    如果先聲明變量 obj,再使用 obj::sum 也是合法的。
public static void main(String[] args) {
    int a = 10;
    int b = 20;
    LambdaTest2 obj = new LambdaTest2();
    runIt(obj::sum, a, b);
}

總結

  • Lambda表達式的前置條件:必須是“函數式接口”
  • 單個參數傳遞時,可以省略參數兩端的括號。參數的類型可以一起省略。
  • 編寫的方式主要包括單行表達式和多行表達式
  • 可以使用方法引用來把多行表達式寫成單行表達式。方法引用又包括了靜態方法引用和動態方法引用。


免責聲明!

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



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