首頁 > 軟體

Java Lambda表示式詳解

2023-02-22 06:00:56

Java Lambda表示式是JDK8引入的,是一個比較重要的特性

Lambda表示式簡介

Lambda 表示式是 JDK8 的一個新特性,也被稱為閉包,Lambda表示式允許把函數作為一個方法的引數,即行為引數化,函數作為引數傳遞進方法中。

Lambda表示式可以取代大部分的匿名內部類,寫出更優雅的 Java 程式碼,尤其在集合的遍歷和其他集合操作中,可以極大地優化程式碼結構。

Lambda表示式的作用

Java 8 引入的 Lambda表示式的主要作用就是簡化程式碼,寫出更優雅的程式碼。

怎麼一個簡化優雅呢,舉一Lambda語法建立執行緒和匿名內部類建立執行緒的例子,就非常清楚了。

1.匿名類建立執行緒

// JDK7匿名內部類寫法
new Thread(new Runnable() {//介面名
        @Override
        public void run() {//方法名
            System.out.println("mikechen");
        }
    });

2.Lambda表示式建立執行緒

// JDK8 Lambda來建立執行緒
new Thread(() -> System.out.println("mikechen"));

上述程式碼跟匿名內部類的作用是一樣的,但比匿名內部類更進一步,這裡連介面名和函數名都一同省掉了,Lambda表示式可以取代匿名內部類,寫出更優雅的程式碼。

Lambda表示式的語法

lambda 表示式的語法格式如下:

  • ():左側部分指定了Lambda表示式需要的所有引數。
  • ->:Lambda表示式的操作符或者箭頭操作符。
  • {}:右側部分指定了Lambda體,即方法需要實現的內容。

1.無引數

Lambda體只有一條語句:

範例:

() -> System.out.println("mikechen");

請注意,括號中沒有內容。那就是表示lambda不帶任何引數。

2.一個引數

範例:

Consumer<String> con = (x) -> System.out.println(x);

當lambda表示式是單個引數時,也可以省略括號,如下所示:

Consumer<String> con = x -> System.out.println(x);

3.多個引數

如果Java lambda表示式匹配的方法有多個引數,則需要在括號內列出這些引數,程式碼如下:

BinaryOperator<Integer> bo = (a, b) -> {
    System.out.println("函數式介面");
    return a + b;
};

注意:僅當方法是單個引數時,才可以省略括號。

4.指定引數型別

如果編譯器無法從lambda匹配的函數式介面抽象方法推斷引數型別,則有時可能需要為lambda表示式指定引數型別。

(Car car) -> System.out.println("The car is: " + car.getName());

如你所見,car引數的型別(Car)寫在引數名稱的前面,就像在其他方法中宣告引數或對介面進行匿名實現時一樣。

5.只有一條語句時

當Lambda體只有一條語句時,return和大括號可以省略,範例:

BinaryOperator<Integer> bo = (a, b) -> a + b;

6.引數型別不寫

Lambda表示式的參數列的資料型別可以省略不寫,因為JVM編譯器能夠通過上下文推斷出資料型別,這就是“型別推斷”,範例:

BinaryOperator<Integer> bo = (Integer a, Integer b) -> {
    return a + b;
};

等同於

BinaryOperator<Integer> bo = (a, b) -> {
    return a + b;
};

上述 Lambda 表示式中的引數型別都是由編譯器推斷得出,Lambda 表示式中無需指定型別,程式依然可以編譯,這是因為 javac 根據程式的上下文,在後臺推斷出了引數的型別。

Lambda 表示式的型別依賴於上下文環境,是由編譯器推斷出來的,這就是所謂的“型別推斷”。

7.Lambda表示式返回值

你可以從Java lambda表示式返回值,就像從方法中返回值一樣。你只需向lambda表示式主體新增一個return,如下所示:

(param) -> {
    System.out.println("param: " + param);
    return "return value";
}

函數式介面

Lambda表示式需要函數式介面的支援,所以,我們有必要來說說什麼是函數式介面。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

一種用於表示一個介面是Java語言規範定義的函數式介面的註解型別。

對於函數式介面,我們可以理解為只有一個抽象方法的介面,除此之外它和別的介面相比並沒有什麼特殊的地方。

public interface MyFunctionInterface<T> {
    public T getValue(T t);
}

為了確保函數式介面的正確性,我們可以給這個介面新增@FunctionalInterface註解,這樣當其中有超過一個抽象方法時就會報錯。

Unexpected @FunctionalInterface annotation
@FunctionalInterface ^ WorkerInterface is not a functional interface multiple
non-overriding abstract methods found in interface WorkerInterface 1 error

Java 8中每一個Lambda表示式必須有一個函數式介面與之對應,也就是說,只要一個物件是函數式介面的範例,那麼該物件就可以用Lambda表示式來表示。

Lambda表示式的舉例

學習 Lambda 表示式的最好方式是學習例子,下面我們看幾個比較常用的例子。

1.lambda建立執行緒

使用() -> {} 替代匿名類:

//JDK 8之前
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("使用匿名內部類,開執行緒");
    }
}).start();

//JDK 8 使用lambda表示式
new Thread(() -> System.out.println("使用lambda表示式,開執行緒")).start();

2.lambda事件處理

使用lambda表示式如下所示寫出更好的事件偵聽器的程式碼:

// Java 8之前:
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button被點選了使用老的方式!");
    }
});

// Java 8方式:
button.addActionListener( (e) -> {
    System.out.println("Button被點選了使用Lambda表示式!");
});

3.lambda遍歷List集合

集合的遍歷,採用lambda表示式會更簡潔:

// Java 8之前:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
    System.out.println(feature);
}

// Java 8之後:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
features.forEach(n -> System.out.println(n));

// 使用Java 8的方法參照更方便,方法參照由::雙冒號操作符標示,
features.forEach(System.out::println);

方法參照是使用兩個冒號::這個操作符號。

4.元素排序

之前我們若要為集合內的元素排序,就必須呼叫 sort 方法,傳入比較器重寫 compare。

方法的比較器物件,現在我們還可以使用 lambda 表示式來簡化程式碼。

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("a");
    list.add("d");
    list.add("b");
    list.add("c");
    list.sort((o1,o2)->o1.compareTo(o2));
    list.forEach(System.out::println);
}

5.lambda Map

// 不使用lambda表示式為每個訂單加上12%的稅
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    System.out.println(price);
}
// 使用lambda表示式
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);

6.lambda過濾String

// 建立一個字串列表,每個字串長度大於2
List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList());
System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);

7.lambda對集合應用函數

// 將字串換成大寫並用逗號連結起來
List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada");
String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
System.out.println(G7Countries);

8.lambda計算最大值、最小值、平均值

//獲取數位的個數、最小值、最大值、總和以及平均值
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest prime number in List : " + stats.getMax());
System.out.println("Lowest prime number in List : " + stats.getMin());
System.out.println("Sum of all prime numbers : " + stats.getSum());
System.out.println("Average of all prime numbers : " + stats.getAverage());

以上就是Java Lambda表示式詳解的詳細內容,更多關於Java Lambda表示式詳解的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com