天天看點

【JDK新特性】一篇搞懂Lambda表達式 & 函數式接口

作者:即興小索奇呀

hello,我是小索奇

你問:JDK新特性(包含Lambda表達式 & 函數式接口 )要學嗎?

我答:當然要學了,如果你以後敲代碼的話,你一定會用到 and 見到,現在學會的話,将來的你一定會感謝現在的你~

用起來你會發現,哇真的好用!在後期學習架構時你也一定會遇到

代碼比較枯燥,現在不想看的可收藏備看~

## 概述

Lambda是JDK8的文法糖。它可以對某些匿名内部類的寫法進行簡化,它是函數式程式設計的一個重要展現。讓我們不用關注什麼是對象,重點關注我們對資料做了什麼操作,可以說它Lambda表達式就是一個對象

- Lambda表達式在C++、C#、Python、Scala等一些語言中也支援,Java支援的還算比較晚的(确實好用)

- Lambda關注的是方法的參數(),還有具體做了什麼{}方法體,中間用-> ,凡是确定的東西都可删除(比如一個内部類,直接确定是它)

## 基本文法

(參數清單)->{代碼}

拓展__匿名内部類

- Runnable是一個接口

- Runnable隻有一個抽象方法

![image-20230717000509143](https://suoqi-1318874292.cos.ap-beijing.myqcloud.com/suoqi/note-img/20230717000510.png)

## LambdaTest代碼示範

```

public class LambdaTest {

@Test

public void test1(){

// Runnable隻有一個抽象方法

Runnable r1 = new Runnable() {

@Override

public void run() {

System.out.println("我愛即興小索奇");

}

};

r1.run();

System.out.println("***********************");

//Lambda表達式

Runnable r2 = () -> {

System.out.println("我是即興小索奇");

};

r2.run();

}

@Test

public void test2(){

Comparator<Integer> com1 = new Comparator<Integer>() {

@Override

public int compare(Integer o1, Integer o2) {

return Integer.compare(o1,o2);

}

};

int compare1 = com1.compare(12,21);

System.out.println(compare1);

System.out.println("***********************");

//Lambda表達式的寫法,箭頭後的{}是可以省略的,參數類型确定也可以省略

Comparator<Integer> com2 = (Integer o1, Integer o2) -> Integer.compare(o1,o2);

// Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1,o2);

int compare2 = com2.compare(23,21);

System.out.println(compare2);

System.out.println("***********************");

//方法引用

Comparator<Integer> com3 = Integer :: compare;

int compare3 = com3.compare(23,21);

System.out.println(compare3);

}

}

```

## LambdaTest01細節示範

```

public class LambdaTest1 {

//文法格式一:無參,無傳回值

@Test

public void test1(){

Runnable r1 = new Runnable() {

@Override

public void run() {

System.out.println("我是即興小索奇");

}

};

r1.run();

System.out.println("***********************");

Runnable r2 = () -> {

System.out.println("即興小索奇運作了");

};

r2.run();

}

//文法格式二:Lambda 需要一個參數,但是沒有傳回值。

@Test

public void test2(){

Consumer<String> con = new Consumer<String>() {

@Override

public void accept(String s) {

System.out.println(s);

}

};

con.accept("小索奇在摸魚!");

System.out.println("*******************");

Consumer<String> con1 = (String s) -> {

System.out.println(s);

};

con1.accept("小索奇正在打怪中...");

}

//文法格式三:資料類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷”

@Test

public void test3(){

Consumer<String> con1 = (String s) -> {

System.out.println(s);

};

con1.accept("小索奇正在探索中...");

System.out.println("*******************");

Consumer<String> con2 = (s) -> {

System.out.println(s);

};

con1.accept("小索奇正在探索中...");

}

@Test

public void test3_1(){

int[] arr = {1,2,3,4}; //類型推斷

HashMap<String,Integer> map = new HashMap<>();//類型推斷

var entrySet = map.entrySet(); //類型推斷 ,在jdk10及之後可以用,現持續存在

}

//文法格式四:Lambda 若隻需要一個參數時,參數的小括号可以省略

@Test

public void test4(){

Consumer<String> con1 = (s) -> {

System.out.println(s);

};

con1.accept("小索奇正在探索中...");

System.out.println("*******************");

Consumer<String> con2 = s -> {

System.out.println(s);

};

con2.accept("小索奇正在睡覺...");

}

//文法格式五:Lambda 需要兩個或以上的參數,多條執行語句,并且可以有傳回值

@Test

public void test5(){

Comparator<Integer> com1 = new Comparator<Integer>() {

@Override

public int compare(Integer o1, Integer o2) {

System.out.println(o1);

System.out.println(o2);

return o1.compareTo(o2);

}

};

System.out.println(com1.compare(12,21));

System.out.println("*****************************");

Comparator<Integer> com2 = (o1, o2) -> {

System.out.println(o1);

System.out.println(o2);

return o1.compareTo(o2);

};

System.out.println(com2.compare(12,21));

}

//文法格式六:當 Lambda 體隻有一條語句時,return 與大括号若有,都可以省略

@Test

public void test6(){

Comparator<Integer> com1 = (o1,o2) -> {

return o1.compareTo(o2);

};

System.out.println(com1.compare(12,6));

System.out.println("*****************************");

Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);

System.out.println(com2.compare(12,16));

}

@Test

public void test7(){

Consumer<String> con1 = s -> {

System.out.println(s);

};

con1.accept("小索奇正在睡大街...");

System.out.println("*****************************");

}

}

```

## 自定義函數式接口

```

@FunctionalInterface

public interface MyFunctionalInterface {

void method();

// void method1();

}

public class MyFunctionalInterfaceTest {

@Test

public void test1(){

MyFunctionalInterface m = () -> System.out.println("hello");

m.method();

}

}

```

## 總結

直達 `java.util.function`文檔:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/function/package-summary.html

1. **Lambda表達式的使用舉例:**

(o1, o2) -> Integer.compare(o1,o2);

2. **Lambda表達式的格式舉例:**

lambda形參清單 -> lambda體

3. **Lambda表達式的格式**

- lambda操作符或箭頭操作符

- -> 的左邊: lambda形參清單,對應着要重寫的接口中的抽象方法的形參清單。

- -> 的右邊: lambda體,對應着接口的實作類要重寫的方法的方法體。

4. **Lambda表達式的本質:**

- 一方面,lambda表達式作為接口的實作類的對象。 --->說白了Lambda表達式就是對象, "萬事萬物皆對象"

另一方面,lambda表達式是一個匿名函數。

5. **函數式接口**

> 什麼是函數式接口?為什麼需要函數式接口?

- 如果接口中隻聲明有一個抽象方法,則此接口就稱為函數式接口(如Runnable就是函數式接口 ,底層加上了`@FunctionalInterface`注解,可以校驗它是一個函數式接口,加了最多就隻能寫一個抽象方法了)

- 因為隻有給函數式接口提供實作類的對象時,我們才可以使用lambda表達式。

> api中函數式接口所在的包

- jdk8中聲明的函數式接口都在java.util.function包下。

> 4個基本的函數式接口

接口 對應的抽象方法

- 消費型接口:Consumer<T> void accept(T t)

消費型接口表示接收一個參數并執行某些操作,但沒有傳回值。它常用于需要執行一些操作但不需要傳回結果的場景,例如周遊集合、修改對象狀态等,例如

```java

Consumer<String> consumer = s -> System.out.println(s);

consumer.accept("hello world");

```

- 供給型接口:Supplier<T> T get()

供給型接口表示不需要接收任何參數,但需要傳回一個結果。它常用于需要生成某些資料的場景,例如生成随機數、擷取目前時間等,例如

```java

Supplier<Integer> supplier = () -> (int) (Math.random() * 100);

System.out.println(supplier.get());

```

- 函數型接口:Function<T,R> R apply(T t)

函數型接口表示接收一個參數并傳回一個結果。它常用于需要對某些資料進行處理并傳回結果的場景,例如字元串轉換、資料加工等。例如:

```java

Function<String, Integer> function = s -> s.length();

System.out.println(function.apply("hello world"));

```

- 判斷型接口:Predicate<T> boolean test(T t)

判斷型接口表示接收一個參數并傳回一個布爾值。它常用于需要對某些資料進行判斷并傳回布爾值的場景,例如過濾集合、判斷對象狀态等,例如

```java

Predicate<Integer> predicate = i -> i > 0;

System.out.println(predicate.test(-1));

```

6. **Lambda表達式的文法規則總結**

- -> 的左邊:lambda形參清單,參數的類型都可以省略。如果形參隻有一個,則一對()也可以省略。

- -> 的右邊:lambda體,對應着重寫的方法的方法體。如果方法體中隻有一行執行語句,則一對{}可以省略。

如果有return關鍵字,則必須一并省略。