自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如果還不懂如何使用 Consumer 接口,來青島我當(dāng)面給你講!

開發(fā) 前端
如果我們想要將公共的部分抽取出來,發(fā)現(xiàn)都比較零散,還不如不抽取,但是不抽取代碼又存在大量重復(fù)的代碼不符合我的風(fēng)格。于是我便將手伸向了 Consumer 接口。

 [[436759]]

背景

沒錯,我還在做 XXXX 項(xiàng)目,還在與第三方對接接口,不同的是這次是對自己業(yè)務(wù)邏輯的處理。

在開發(fā)過程中我遇到這么一個問題:

表結(jié)構(gòu):一張主表A ,一張關(guān)聯(lián)表B ,表 A 中存儲著表 B 記錄的狀態(tài)。

場景:第一步創(chuàng)建主表數(shù)據(jù),插入A表;第二步調(diào)用第三方接口插入B表同時更新A表的狀態(tài)。此時大家應(yīng)該都會想到在進(jìn)行第二步的時候需要做好數(shù)據(jù)的冪等性。這樣的話就會存在以下幾種情況:

一、B表中不存在與A表關(guān)聯(lián)的數(shù)據(jù),此時需要調(diào)用第三方接口,插入B表同時更新A表的狀態(tài);

二、B表中存在與A表關(guān)聯(lián)的數(shù)據(jù);

A表中的狀態(tài)為處理中:直接返回處理中字樣;

A表中的狀態(tài)為處理成功:直接返回成功的字樣;

A表中的狀態(tài)為處理失?。捍藭r需要調(diào)用第三方接口,更新B表同時更新A表的狀態(tài);

代碼實(shí)現(xiàn)

首先我是這樣編寫的偽代碼

  1. B b = this.baseMapper.selectOne(queryWrapper); 
  2. if (b != null) { 
  3.  String status = b.getStatus(); 
  4.  if (Objects.equals(Constants.STATUS_ING, status)){ 
  5.   return "處理中"
  6.  } else if (Objects.equals(Constants.STATUS_SUCCESS, status)){ 
  7.   return "處理成功"
  8.  } 
  9.  //失敗的操作 
  10.  //請求第三方接口并解析響應(yīng)結(jié)果 
  11.  ...... 
  12.  if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) { 
  13.         ...... 
  14.         //更新B表操作 
  15.   bb.setStatus(Constants.STATUS_ING); 
  16.   mapper.updateById(bb); 
  17.  
  18.   //更新A表的狀態(tài) 
  19.   a.setStatus(Constants.STATUS_ING); 
  20.   aMapper.updateById(a); 
  21.  } 
  22.   
  23. else { 
  24.  //請求第三方接口并解析響應(yīng)結(jié)果 
  25.  ...... 
  26.  if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) { 
  27.         ...... 
  28.         //插入B表操作 
  29.   bb.setStatus(Constants.STATUS_ING); 
  30.   mapper.insert(bb); 
  31.  
  32.   //更新A表的狀態(tài) 
  33.   a.setStatus(Constants.STATUS_ING); 
  34.   aMapper.updateById(a); 
  35.  } 

不知道細(xì)心的小伙伴是否發(fā)現(xiàn),存在B表記錄并且狀態(tài)為“失敗”的情況和不存在B表的情況除了插入B表或者更新B表的操作之外,其余的操作都是相同的。

如果我們想要將公共的部分抽取出來,發(fā)現(xiàn)都比較零散,還不如不抽取,但是不抽取代碼又存在大量重復(fù)的代碼不符合我的風(fēng)格。于是我便將手伸向了 Consumer 接口。

更改之后的偽代碼

  1. B b = this.baseMapper.selectOne(queryWrapper); 
  2. if (b != null) { 
  3.  String status = b.getStatus(); 
  4.  if (Objects.equals(Constants.STATUS_ING, status)){ 
  5.   return "處理中"
  6.  } else if (Objects.equals(Constants.STATUS_SUCCESS, status)){ 
  7.   return "處理成功"
  8.  } 
  9.  //失敗的操作 
  10.  getResponse(dto, response, s -> mapper.updateById(s)); 
  11. else { 
  12.  getResponse(dto, response, s -> mapper.updateById(s)); 
  13.  
  14. public void getResponse(DTO dto, Response response, Consumer<B> consumer){ 
  15.  //請求第三方接口并解析響應(yīng)結(jié)果 
  16.  ...... 
  17.  if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) { 
  18.         ...... 
  19.   bb.setStatus(Constants.STATUS_ING); 
  20.   
  21.   consumer.accept(bb); 
  22.  
  23.   //更新A表的狀態(tài) 
  24.   a.setStatus(Constants.STATUS_ING); 
  25.   aMapper.updateById(a); 
  26.  } 

看到這,如果大家都已經(jīng)看懂了,那么恭喜你,說明你對 Consumer 的使用已經(jīng)全部掌握了。如果你還存在一絲絲的疑慮,那么就接著往下看,我們將介紹一下四種常見的函數(shù)式接口。

函數(shù)式接口

那什么是函數(shù)式接口呢?函數(shù)式接口是只有一個抽象方法(Object的方法除外),但是可以有多個非抽象方法的接口,它表達(dá)的是一種邏輯上的單一功能。

@FunctionalInterface

@FunctionalInterface 注解用來表示該接口是函數(shù)式接口。它有助于及早發(fā)現(xiàn)函數(shù)式接口中出現(xiàn)的或接口繼承的不適當(dāng)?shù)姆椒暶鳌?/p>

如果接口用該注解來注釋,但實(shí)際上不是函數(shù)式接口,則會在編譯時報(bào)錯。

Consumer

我們一般稱之為“消費(fèi)者”,它表示接受單個輸入?yún)?shù)但不返回結(jié)果的操作。不同于其它函數(shù)式接口,Consumer 預(yù)期通過副作用進(jìn)行操作。

那什么又是副作用呢?說一下我所理解的副作用,副作用其實(shí)就是一個函數(shù)是否會修改它范圍之外的資源,如果有就叫有副作用,反之為沒有副作用。比如修改全局變量,修改輸入?yún)?shù)所引用的對象等。

  1. @FunctionalInterface 
  2. public interface Consumer<T> { 
  3.  
  4.     /** 
  5.      *  對給定的參數(shù)執(zhí)行此操作。 
  6.      */ 
  7.     void accept(T t); 
  8.  
  9.     /** 
  10.      *  
  11.      *  返回一個組合的 Consumer ,依次執(zhí)行此操作,然后執(zhí)行after操作。 
  12.      *  如果執(zhí)行任一操作會拋出異常,它將被轉(zhuǎn)發(fā)到組合操作的調(diào)用者。 
  13.      *  如果執(zhí)行此操作會引發(fā)異常,則不會執(zhí)行after操作。 
  14.      */ 
  15.     default Consumer<T> andThen(Consumer<? super T> after) { 
  16.         Objects.requireNonNull(after); 
  17.         return (T t) -> { accept(t); after.accept(t); }; 
  18.     } 

正如我們案例中遇到的場景,我們只需要將要執(zhí)行的邏輯方法當(dāng)作參數(shù)傳入 getResponse() 中,然后在該方法中執(zhí)行 accept() 方法進(jìn)行消費(fèi)即可。如果還不理解,我們可以把它轉(zhuǎn)換為匿名內(nèi)部類的調(diào)用方式。

  1. getResponse(dto, response, new Consumer<B>() { 
  2.    @Override 
  3.    public void accept(B bb) { 
  4.      mapper.insert(bb); 
  5.    } 
  6. ); 

當(dāng)調(diào)用accept() 方法的時候就會去調(diào)用匿名內(nèi)部類的方法了,也就是我們傳入 getResponse() 的邏輯方法。

Supplier

我們一般稱之為“生產(chǎn)者”,沒有參數(shù)輸入,但是能返回結(jié)果,為結(jié)果的提供者。

  1. @FunctionalInterface 
  2. public interface Supplier<T> { 
  3.  
  4.     /** 
  5.      *  獲取一個結(jié)果 
  6.      */ 
  7.     T get(); 

可以舉個簡單的例子感受下:

  1. Optional<Double> optional = Optional.empty(); 
  2. optional.orElseGet(()->Math.random() ); 
  3.  
  4. //orElseGet 方法的源碼,里邊用到了 get 方法 
  5. public T orElseGet(Supplier<? extends T> other) {    
  6.     return value != null ? value : other.get(); 

Function

我把它稱為“轉(zhuǎn)換者”,表示接收一個參數(shù)通過處理之后返回一個結(jié)果的函數(shù)。

  1. @FunctionalInterface 
  2. public interface Function<T, R> { 
  3.  
  4.     /** 
  5.      *  將 T 類型的參數(shù)傳入,經(jīng)過函數(shù)表達(dá)式的計(jì)算,返回 R 類型的結(jié)果 
  6.      */ 
  7.     R apply(T t); 
  8.  
  9.     /** 
  10.      * 返回一個組合函數(shù),先將參數(shù)應(yīng)用于 before 函數(shù),然后將結(jié)果應(yīng)用于當(dāng)前函數(shù),返回最終結(jié)果。 
  11.      * 如果對任一函數(shù)的求值引發(fā)異常,則會將其轉(zhuǎn)發(fā)給組合函數(shù)的調(diào)用方。 
  12.      */ 
  13.     default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { 
  14.         Objects.requireNonNull(before); 
  15.         return (V v) -> apply(before.apply(v)); 
  16.     } 
  17.  
  18.     /** 
  19.      * 返回一個組合函數(shù),先將參數(shù)應(yīng)用與當(dāng)前函數(shù),然后將結(jié)果應(yīng)用于 after 函數(shù),返回最終的結(jié)果。 
  20.      * 如果對任一函數(shù)的求值引發(fā)異常,則會將其轉(zhuǎn)發(fā)給組合函數(shù)的調(diào)用方。  
  21.      */ 
  22.     default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { 
  23.         Objects.requireNonNull(after); 
  24.         return (T t) -> after.apply(apply(t)); 
  25.     } 
  26.  
  27.     /** 
  28.      *  返回始終返回其輸入?yún)?shù)的函數(shù)。 
  29.      */ 
  30.     static <T> Function<T, T> identity() { 
  31.         return t -> t; 
  32.     } 

我們在 lambda 表達(dá)式中應(yīng)用比較多,所以我們來簡單演示下:

  1. @Data 
  2. @AllArgsConstructor 
  3. public class Teacher { 
  4.     private String name
  5.     private int age; 
  6.  
  7. public class TeacherTest { 
  8.     public static void main(String[] args) { 
  9.        List<Teacher> list = Arrays.asList( 
  10.             new Teacher("張三",25), 
  11.             new Teacher("李四",28), 
  12.             new Teacher("王五",18)); 
  13.       List<String> collect = list.stream().map(item -> item.getName()).collect(Collectors.toList()); 
  14.       System.out.println(collect); 
  15.     } 

其中 map 接收的參數(shù)就是 Function 類型, item 為傳入?yún)?shù),item.getName() 為返回處理的結(jié)果,最后輸出結(jié)果為

  1. [張三, 李四, 王五] 

Predicate

我們稱之為“判斷者”,通過接收參數(shù) T 來返回 boolean 的結(jié)果。

  1. @FunctionalInterface 
  2. public interface Predicate<T> { 
  3.  
  4.     /** 
  5.      *  接收一個參數(shù), 判斷這個參數(shù)是否匹配某種規(guī)則, 匹配成功返回true, 匹配失敗則返回false 
  6.      */ 
  7.     boolean test(T t); 
  8.  
  9.     /** 
  10.      *  接收一個 Predicate 類型的參數(shù),用當(dāng)前函數(shù)和 other 函數(shù)邏輯與判斷參數(shù) t 是否匹配規(guī)則,成功返回true,失敗返回 false  
  11.      *  如果當(dāng)前函數(shù)返回 false,則 other 函數(shù)不進(jìn)行計(jì)算 
  12.      * 在評估 Predicate 期間引發(fā)的任何異常都會轉(zhuǎn)發(fā)給調(diào)用方 
  13.      */ 
  14.     default Predicate<T> and(Predicate<? super T> other) { 
  15.         Objects.requireNonNull(other); 
  16.         return (t) -> test(t) && other.test(t); 
  17.     } 
  18.  
  19.     /** 
  20.      *  返回當(dāng)前Predicate取反操作之后的Predicate 
  21.      */ 
  22.     default Predicate<T> negate() { 
  23.         return (t) -> !test(t); 
  24.     } 
  25.  
  26.     /** 
  27.      *  接收一個 Predicate 類型的參數(shù),用當(dāng)前函數(shù)和 other 函數(shù) 邏輯或 判斷參數(shù) t 是否匹配規(guī)則,成功返回true,失敗返回 false  
  28.      *  如果當(dāng)前函數(shù)返回 true,則 other 函數(shù)不進(jìn)行計(jì)算 
  29.      * 在評估 Predicate 期間引發(fā)的任何異常都會轉(zhuǎn)發(fā)給調(diào)用方 
  30.      */ 
  31.     default Predicate<T> or(Predicate<? super T> other) { 
  32.         Objects.requireNonNull(other); 
  33.         return (t) -> test(t) || other.test(t); 
  34.     } 
  35.  
  36.     /** 
  37.      *  靜態(tài)方法:傳入一個參數(shù),用來生成一個 Predicate,調(diào)用test() 方法時調(diào)的 object -> targetRef.equals(object) 函數(shù)式 
  38.      * 
  39.      */ 
  40.     static <T> Predicate<T> isEqual(Object targetRef) { 
  41.         return (null == targetRef) 
  42.                 ? Objects::isNull 
  43.                 : object -> targetRef.equals(object); 
  44.     } 

相信大家在編碼過程中經(jīng)常會遇到該函數(shù)式接口,我們舉個例子來說一下:

  1. public static void main(String[] args) { 
  2.     List<Teacher> list = Arrays.asList( 
  3.         new Teacher("張三",25), 
  4.         new Teacher("李四",28), 
  5.         new Teacher("王五",18)); 
  6.  
  7.     list = list.stream().filter(item -> item.getAge()>25).collect(Collectors.toList()); 
  8.     list.stream().forEach(item->System.out.println(item.getName())); 

其中 filter() 的參數(shù)為 Predicate 類型的,返回結(jié)果為:李四

看到這兒,我們常見的四種函數(shù)式接口就已經(jīng)介紹完了。說實(shí)話,函數(shù)式接口我已經(jīng)看過好幾遍了,尤其是 Consumer 和 Supplier。當(dāng)時只是腦子里學(xué)會了,沒有應(yīng)用到具體的項(xiàng)目中,下次再遇到的時候還是一臉懵逼,不知道大家有沒有這種感受。

所以我們需要總結(jié)經(jīng)驗(yàn)教訓(xùn),一定要將代碼的原理搞懂,然后多敲幾遍,爭取應(yīng)用到自己的項(xiàng)目中,提升自己的編碼能力。

本文轉(zhuǎn)載自微信公眾號「阿Q說代碼」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系阿Q說代碼公眾號。

 

責(zé)任編輯:武曉燕 來源: 阿Q說代碼
相關(guān)推薦

2021-09-06 07:58:47

鏈表數(shù)據(jù)結(jié)構(gòu)

2023-08-09 09:03:49

CPU密集型運(yùn)算

2016-03-17 09:55:52

HDFSHadoop分布式文件系統(tǒng)

2021-06-02 08:17:05

門面模式設(shè)計(jì)

2023-11-02 08:27:29

2023-11-29 13:59:00

trait定義接口

2024-03-06 11:14:13

ViteReact微前端

2020-10-14 10:29:58

人工智能

2015-11-12 09:47:28

2021-04-20 11:40:47

指針類型CPU

2019-06-19 09:07:06

HTTP代理協(xié)議

2020-02-24 21:50:24

瓶頸數(shù)據(jù)庫

2022-01-05 09:40:03

DIff算法前端

2020-12-16 06:33:06

thisJava調(diào)用

2024-04-08 08:40:32

RBACJenkins配置

2024-05-16 10:59:16

Vue項(xiàng)目前端

2020-05-20 22:13:26

JVM加載機(jī)制虛擬機(jī)

2023-05-15 08:02:33

Kafka選舉Broker

2022-08-01 21:38:25

Linux fmt命令

2022-05-08 13:05:22

職位產(chǎn)品經(jīng)理開源
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號