# 常用的函數式接口
## 回顧
函數接口的概念在之前的文章《Lambda表達式》中就有提到,函數接口配合Lambda表達式的使用在一些情況下可以大大簡化java代碼的書寫。函數接口指的就是接口中只有一個抽象方法, 并且接口使用@FunctionalInterface注解進行修飾。JDK中幫我們定義好了一些常用的函數接口,這些函數接口配合Lambda和后面要講的stream流進行一些**過濾數據**的操作,用起來非常簡潔。常用在“作為參數傳遞給一個方法”的場景中。下面就來講常用到的函數接口有哪些。
## Supplier接口
(supplier 供應商)是一個"工廠"類型接口,用來"生產"對應的數據類型,不用傳入任何數據。具體使用在后面的stream流中可以體現。
~~~
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
~~~
### 抽象方法
> T get():用來獲取一個泛型參數類型指定的數據,即用來提供一個符合要求的數據類型,"生產"一個數據,就跟"供應商"一樣。
舉例:獲取一個數組中的最大值
```java
public class SupplierDemo {
public static int getMaxValue(Supplier<Integer> supplier) { //接口作為參數進行傳遞
return supplier.get();
}
public static void main(String[] args) {
int[] nums = {2, 9, 19, 1, 20};
int max = getMaxValue(()->{ //使用Lambad表達式
int max = nums[0];
for (int i = 1; i < nums.length; i++) {
max = nums[i] > max ? nums[i] : max;
}
return max;
});
}
}
```
get()方法的目的就是給我們提供一個想要的數據類型。
## Consumer接口
Consumer接口具有和Supplier接口相反的功能,主要是為了消費一個數據。
~~~
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
~~~
### 抽象方法
> void accept(T):對給定的參數執行該方法的內容。
舉例:將傳遞的字符串數據進行逆轉
```java
public class ConsumerDemo {
public static void reserveString(String str, Consumer<String> con) {
con.accept(str);
}
public static void main(String[] args) {
String str = "lambda";
reserveString(str, (str)->{
System.out.println(str); //lambda
StringBuffer reStr = new StringBuffer(str);
reStr.reverse().toString(); //將字符串進行逆轉
System.out.println(reStr); //adbmal
});
}
}
```
### 默認方法
與Supplier接口不同的是,Consumer接口中實現了一個默認的方法,addThen()
```java
/**
* 默認方法
* 1. 返回一個組合的Consumer對象,并且會按照順序執行accept方法:即可以拼接多個進行執行
* 2. 如果after方法執行出現異常(或接下去拼接的出現異常了)就會將該異常轉發給調用者(例如main)。
* 3. 如果執行this操作出現異常時,不會執行after的操作。
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after); //判斷是否為空指針
return (T t) -> {
accept(t);
after.accept(t);
}; //這也是一個Consumer接口accept的lambad實現
}
```
舉例:將一個字符串轉化為大小寫
```java
public class ConsumerDemo {
public static void method(String str, Consumer<String> con1, Consumer<String> con2) {
con1.andThen(con2).accept(str);
}
public static void main(String[] args) {
String str = "Lambda";
method(str, (t)->{
System.out.println(t.toUpperCase()); //LAMBDA
}, (t) -> {
System.out.println(t.toLowerCase()); //lambda
});
}
}
```
可以使用默認方法實現一個責任鏈模式。
## Predicate接口
(Predicate 謂詞,離散數學中的概念),傳入一個參數,對參數進行邏輯判斷,看參數是否符合條件(在給定的參數上評估這個謂詞),返回值為boolean。
```java
@FunctionalInterface
public interface Predicate<T> { }
```
### 抽象接口
> boolean test(T t):判斷傳入的參數是否符合條件
舉例:傳入一個字符串列表,打印長度大于4的字符串
```java
public class PredicateDemo {
public static void checkString(String[] strs, Predicate<String> pre) {
for (int i = 0; i < strs.length; i++) {
if (pre.test(strs[i])) {
System.out.println(strs[i]);
}
}
}
public static void main(String[] args) {
String[] strs = {"java", "c", "C++", "python", "javascript", "Typescript"};
checkString(strs, (str)->{
return str.length() > 4;
}); //python, javascript,Typescript
}
}
```
### 默認方法
既然是用來進行邏輯判斷的,少不了要用到邏輯運算符,Predicate接口里面就內置了一些默認的邏輯運算方法:
```java
/**
* 1.返回一個通過邏輯與組合的Predicate接口
* 2.other.test拋出異常的話將該異常轉發給調用者
* 3.this.test拋出異常的話不執行other.test的內容
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
//邏輯非
default Predicate<T> negate() {
return (t) -> !test(t);
}
//邏輯或
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
```
舉例:判斷字符串包含a并且長度大于5
```java
public class PredicateDemo {
public static boolean checkString(String str, Predicate<String> pre1, Predicate<String> pre2) {
return pre1.and(pre2).test(str);
}
public static void main(String[] args) {
String str = "lambda";
boolean b = checkString(str, (str1)->{
return str1.length() > 5;
}, (str1) -> {
return str1.contains("a");
});
System.out.println(b); // true
}
}
```
## Function接口
```java
@FunctionalInterface
public interface Function<T, R> {}
```
該接口用來將類型T轉化為類型R,T稱為前置條件,R稱為后置條件
### 抽象方法
> R apply(T t):將給定參數類型T轉化為R類型
例如,將String類型數字轉化為Integer類型
```java
public class FunctionDemo {
private static void transform(Function<String, Integer> function) {
int num = function.apply("10"); //數字10
System.out.println(num + 20);
}
public static void main(String[] args) {
transform(s ‐> Integer.parseInt(s));
}
}
```
### 默認方法
與Consumer類似的,Function也有一個addThen方法,該方法也是返回一個組合操作后的Function接口,最終轉化的數據類型與after轉化的數據類型一致。
```java
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after); //判斷是否為空指針
return (T t) -> after.apply(apply(t)); //這也是一個Consumer接口apply的lambad實現
}
```
舉例:將字符串數字轉化為Integer類型后+10再轉化為字符串
```java
public class FunctionDemo{
public static void addTen(String str, Function<String, Integer> fun1, Function<Integer, String> fun2) { //注意最后返回的與fun2的類型相同
String s = fun1.andThen(fun2).apply(str);
System.out.println(s); //"20"
}
public static void main(String[] args) {
String s = "10";
addTen(s, (String str1) ->{
return Integer.parseInt(str1) + 10;
}, (Integer integer) -> {
return integer.toString();
});
}
}
```
## 小結
1. 通過函數式接口,我們可以看到lambda表達式的簡潔之處。
2. 雖然現階段我們可能會覺得這么進行操作多此一舉,但是這些接口在后面的stream流就有很大的用處。
- 第一章 Java基礎
- ThreadLocal
- Java異常體系
- Java集合框架
- List接口及其實現類
- Queue接口及其實現類
- Set接口及其實現類
- Map接口及其實現類
- JDK1.8新特性
- Lambda表達式
- 常用函數式接口
- stream流
- 面試
- 第二章 Java虛擬機
- 第一節、運行時數據區
- 第二節、垃圾回收
- 第三節、類加載機制
- 第四節、類文件與字節碼指令
- 第五節、語法糖
- 第六節、運行期優化
- 面試常見問題
- 第三章 并發編程
- 第一節、Java中的線程
- 第二節、Java中的鎖
- 第三節、線程池
- 第四節、并發工具類
- AQS
- 第四章 網絡編程
- WebSocket協議
- Netty
- Netty入門
- Netty-自定義協議
- 面試題
- IO
- 網絡IO模型
- 第五章 操作系統
- IO
- 文件系統的相關概念
- Java幾種文件讀寫方式性能對比
- Socket
- 內存管理
- 進程、線程、協程
- IO模型的演化過程
- 第六章 計算機網絡
- 第七章 消息隊列
- RabbitMQ
- 第八章 開發框架
- Spring
- Spring事務
- Spring MVC
- Spring Boot
- Mybatis
- Mybatis-Plus
- Shiro
- 第九章 數據庫
- Mysql
- Mysql中的索引
- Mysql中的鎖
- 面試常見問題
- Mysql中的日志
- InnoDB存儲引擎
- 事務
- Redis
- redis的數據類型
- redis數據結構
- Redis主從復制
- 哨兵模式
- 面試題
- Spring Boot整合Lettuce+Redisson實現布隆過濾器
- 集群
- Redis網絡IO模型
- 第十章 設計模式
- 設計模式-七大原則
- 設計模式-單例模式
- 設計模式-備忘錄模式
- 設計模式-原型模式
- 設計模式-責任鏈模式
- 設計模式-過濾模式
- 設計模式-觀察者模式
- 設計模式-工廠方法模式
- 設計模式-抽象工廠模式
- 設計模式-代理模式
- 第十一章 后端開發常用工具、庫
- Docker
- Docker安裝Mysql
- 第十二章 中間件
- ZooKeeper