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關鍵字,則必須一并省略。