成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

 [[436759]]

背景

沒錯,我還在做 XXXX 項目,還在與第三方對接接口,不同的是這次是對自己業務邏輯的處理。

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

表結構:一張主表A ,一張關聯表B ,表 A 中存儲著表 B 記錄的狀態。

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

一、B表中不存在與A表關聯的數據,此時需要調用第三方接口,插入B表同時更新A表的狀態;

二、B表中存在與A表關聯的數據;

A表中的狀態為處理中:直接返回處理中字樣;

A表中的狀態為處理成功:直接返回成功的字樣;

A表中的狀態為處理失敗:此時需要調用第三方接口,更新B表同時更新A表的狀態;

代碼實現

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

  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.  //請求第三方接口并解析響應結果 
  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表的狀態 
  19.   a.setStatus(Constants.STATUS_ING); 
  20.   aMapper.updateById(a); 
  21.  } 
  22.   
  23. else { 
  24.  //請求第三方接口并解析響應結果 
  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表的狀態 
  33.   a.setStatus(Constants.STATUS_ING); 
  34.   aMapper.updateById(a); 
  35.  } 

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

如果我們想要將公共的部分抽取出來,發現都比較零散,還不如不抽取,但是不抽取代碼又存在大量重復的代碼不符合我的風格。于是我便將手伸向了 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.  //請求第三方接口并解析響應結果 
  16.  ...... 
  17.  if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) { 
  18.         ...... 
  19.   bb.setStatus(Constants.STATUS_ING); 
  20.   
  21.   consumer.accept(bb); 
  22.  
  23.   //更新A表的狀態 
  24.   a.setStatus(Constants.STATUS_ING); 
  25.   aMapper.updateById(a); 
  26.  } 

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

函數式接口

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

@FunctionalInterface

@FunctionalInterface 注解用來表示該接口是函數式接口。它有助于及早發現函數式接口中出現的或接口繼承的不適當的方法聲明。

如果接口用該注解來注釋,但實際上不是函數式接口,則會在編譯時報錯。

Consumer

我們一般稱之為“消費者”,它表示接受單個輸入參數但不返回結果的操作。不同于其它函數式接口,Consumer 預期通過副作用進行操作。

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

  1. @FunctionalInterface 
  2. public interface Consumer<T> { 
  3.  
  4.     /** 
  5.      *  對給定的參數執行此操作。 
  6.      */ 
  7.     void accept(T t); 
  8.  
  9.     /** 
  10.      *  
  11.      *  返回一個組合的 Consumer ,依次執行此操作,然后執行after操作。 
  12.      *  如果執行任一操作會拋出異常,它將被轉發到組合操作的調用者。 
  13.      *  如果執行此操作會引發異常,則不會執行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.     } 

正如我們案例中遇到的場景,我們只需要將要執行的邏輯方法當作參數傳入 getResponse() 中,然后在該方法中執行 accept() 方法進行消費即可。如果還不理解,我們可以把它轉換為匿名內部類的調用方式。

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

當調用accept() 方法的時候就會去調用匿名內部類的方法了,也就是我們傳入 getResponse() 的邏輯方法。

Supplier

我們一般稱之為“生產者”,沒有參數輸入,但是能返回結果,為結果的提供者。

  1. @FunctionalInterface 
  2. public interface Supplier<T> { 
  3.  
  4.     /** 
  5.      *  獲取一個結果 
  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

我把它稱為“轉換者”,表示接收一個參數通過處理之后返回一個結果的函數。

  1. @FunctionalInterface 
  2. public interface Function<T, R> { 
  3.  
  4.     /** 
  5.      *  將 T 類型的參數傳入,經過函數表達式的計算,返回 R 類型的結果 
  6.      */ 
  7.     R apply(T t); 
  8.  
  9.     /** 
  10.      * 返回一個組合函數,先將參數應用于 before 函數,然后將結果應用于當前函數,返回最終結果。 
  11.      * 如果對任一函數的求值引發異常,則會將其轉發給組合函數的調用方。 
  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.      * 返回一個組合函數,先將參數應用與當前函數,然后將結果應用于 after 函數,返回最終的結果。 
  20.      * 如果對任一函數的求值引發異常,則會將其轉發給組合函數的調用方。  
  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.      *  返回始終返回其輸入參數的函數。 
  29.      */ 
  30.     static <T> Function<T, T> identity() { 
  31.         return t -> t; 
  32.     } 

我們在 lambda 表達式中應用比較多,所以我們來簡單演示下:

  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 接收的參數就是 Function 類型, item 為傳入參數,item.getName() 為返回處理的結果,最后輸出結果為

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

Predicate

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

  1. @FunctionalInterface 
  2. public interface Predicate<T> { 
  3.  
  4.     /** 
  5.      *  接收一個參數, 判斷這個參數是否匹配某種規則, 匹配成功返回true, 匹配失敗則返回false 
  6.      */ 
  7.     boolean test(T t); 
  8.  
  9.     /** 
  10.      *  接收一個 Predicate 類型的參數,用當前函數和 other 函數邏輯與判斷參數 t 是否匹配規則,成功返回true,失敗返回 false  
  11.      *  如果當前函數返回 false,則 other 函數不進行計算 
  12.      * 在評估 Predicate 期間引發的任何異常都會轉發給調用方 
  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.      *  返回當前Predicate取反操作之后的Predicate 
  21.      */ 
  22.     default Predicate<T> negate() { 
  23.         return (t) -> !test(t); 
  24.     } 
  25.  
  26.     /** 
  27.      *  接收一個 Predicate 類型的參數,用當前函數和 other 函數 邏輯或 判斷參數 t 是否匹配規則,成功返回true,失敗返回 false  
  28.      *  如果當前函數返回 true,則 other 函數不進行計算 
  29.      * 在評估 Predicate 期間引發的任何異常都會轉發給調用方 
  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.      *  靜態方法:傳入一個參數,用來生成一個 Predicate,調用test() 方法時調的 object -> targetRef.equals(object) 函數式 
  38.      * 
  39.      */ 
  40.     static <T> Predicate<T> isEqual(Object targetRef) { 
  41.         return (null == targetRef) 
  42.                 ? Objects::isNull 
  43.                 : object -> targetRef.equals(object); 
  44.     } 

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

  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() 的參數為 Predicate 類型的,返回結果為:李四

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

所以我們需要總結經驗教訓,一定要將代碼的原理搞懂,然后多敲幾遍,爭取應用到自己的項目中,提升自己的編碼能力。

本文轉載自微信公眾號「阿Q說代碼」,可以通過以下二維碼關注。轉載本文請聯系阿Q說代碼公眾號。

 

責任編輯:武曉燕 來源: 阿Q說代碼
相關推薦

2021-09-06 07:58:47

鏈表數據結構

2023-08-09 09:03:49

CPU密集型運算

2024-03-06 11:14:13

ViteReact微前端

2023-11-02 08:27:29

2021-06-02 08:17:05

門面模式設計

2016-03-17 09:55:52

HDFSHadoop分布式文件系統

2015-11-12 09:47:28

2020-10-14 10:29:58

人工智能

2023-11-29 13:59:00

trait定義接口

2024-05-16 10:59:16

Vue項目前端

2020-02-24 21:50:24

瓶頸數據庫

2019-06-19 09:07:06

HTTP代理協議

2021-04-20 11:40:47

指針類型CPU

2020-12-16 06:33:06

thisJava調用

2022-08-01 21:38:25

Linux fmt命令

2022-01-05 09:40:03

DIff算法前端

2024-04-08 08:40:32

RBACJenkins配置

2022-05-08 13:05:22

職位產品經理開源

2020-05-20 22:13:26

JVM加載機制虛擬機

2023-05-15 08:02:33

Kafka選舉Broker
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久精品免费一区二区三 | 国产蜜臀97一区二区三区 | 一区二区三区国产 | 日韩久久久久久久久久久 | 国产成人在线视频播放 | 国产精品成人在线播放 | 成人免费一区二区三区视频网站 | 天堂素人约啪 | 亚洲三区在线观看 | 亚洲xxxxx | 亚洲精品一区二 | 色眯眯视频在线观看 | 国产精品成人一区二区三区夜夜夜 | 91在线观看 | 国产美女在线观看 | 97精品超碰一区二区三区 | 色av一区二区 | 日本一区二区高清不卡 | 日韩精品一区二区久久 | 国产成人精品一区二 | 成人在线免费av | 国产乱码精品一品二品 | 激情 一区| 午夜性色a√在线视频观看9 | 久草成人 | 亚洲精品v | 99热在线观看精品 | .国产精品成人自产拍在线观看6 | 一区二区伦理电影 | 欧美国产精品一区二区 | 久久久久久久一区 | 精品乱子伦一区二区三区 | 欧美精品一区在线 | 草草视频在线免费观看 | 日韩一区二区三区在线视频 | 国产综合精品 | 在线观看涩涩视频 | 国产精品亚洲综合 | 婷婷色综合 | 看片国产 | 久久国产精品色av免费观看 |