咱們在工做中不免會寫一些重複性的代碼,因此須要咱們具有必定的抽象能力,好比把共同的邏輯抽取到抽象類中,也能夠經過一些工具類來避免冗餘代碼java
今天這篇文章就是把一個調用服務的重試功能抽取出一個工具類,以備複用。這裏爲了方便介紹,把調用服務簡化成方法的調用,被調用的 foo 方法以下:app
public static List<String> foo() {// 沒有顯示拋出異常 System.out.println("調用方法"); // 模擬拋出異常 System.out.println(1/0); List<String> list = new ArrayList<>(); list.add("1"); return list; }
調用方和重試邏輯以下:函數
List<String> result = null; // 重試次數 int retryCount = 0; // 調用服務的開關,默認打開 boolean callSwitch = true; // 只要調用服務開關開着,而且重試次數不大於最大的重試次數,就調用服務 while (callSwitch && retryCount <= 3) { try { // 調用服務 result = foo(); // 省略了對結果的校驗,假設到了這裏就說明沒有問題,把調用服務開關關掉 callSwitch = false; } catch (Exception e) { // 發生了異常(好比超時,就須要重試了) // 調用服務的開關打開 callSwitch = true; retryCount++; } } // 後面對 result 進行處理
其實上面的代碼就已經解決了,服務重試的邏輯,測試沒有問題後,能夠提交代碼讓同事幫忙進行 CR 了,但是小朋同窗看到這個代碼後,給了建議:工具
能夠抽象一層,提出一個 retry 的工具類,這樣你們均可以簡單複用你的 retry 邏輯測試
白牙心想,也對哈,那就提出一個工具類吧,但是發了會兒呆,居然沒有頭緒(反映出了抽象能力的薄弱,平時要多注意抽象能力的培養)。小朋見狀,給了一點提示,白牙立馬在鍵盤上噼裏啪啦敲擊了起來,就有了下面的工具類編碼
主要依賴函數式接口 Supplier 和 BiFunctioncode
public class RetryUtil { public static <T> T retry(int maxRetryCount, Supplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) { T result = null; Exception exception = null; int retryCount = 0; boolean callMethod = true; while (callMethod && retryCount <= maxRetryCount) { try { // 獲取調用服務的結果 result = supplier.get(); } catch (Exception e) { // 若是重試次數不小於最大重試次數,就拋出異常,咱們把對異常的處理交給業務方 if (retryCount >= maxRetryCount) { throw e; } exception = e; } // 對結果進行判斷 callMethod = consumer.apply(result, exception); if (callMethod) { retryCount++; } } return result; } }
業務調用方的代碼以下:接口
List<String> result1 = retry(3,// 最大重試次數 ()-> foo(),// 調用服務 (list, e) -> e != null || list == null || list.isEmpty());// 對結果處理
自測沒有問題後,又提交代碼讓小朋給 CR 一下,小朋凝視了會兒,就有了下面的對話開發
小朋:「retry 方法沒有拋出異常」get
白牙:「被調用的服務沒有顯示的拋出異常,這裏也就沒有拋出」
小朋:「那人若是有服務方顯示拋出異常呢?」
白牙:「我再改一版」
服務方顯示拋出了異常,這樣 retry 方法也得顯示拋出異常,但調用方就會顯示會處理的異常,以下所示:
public static List<String> foo() throws Exception{// 顯示拋出異常 System.out.println("調用方法"); // 模擬拋出異常 System.out.println(1/0); List<String> list = new ArrayList<>(); list.add("1"); return list; }
public class RetryUtil { public static <T> T retry(int maxRetryCount, Supplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) throws Exception{ // 省略... }
出現這種狀況是由於 Supplier 的 get 方法沒有拋出異常
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
既然你不支持,那就本身寫個唄,因而就有了下面的 DspSupplier,它和 Supplier 的主要區別就是在 get 方法中顯示拋出了異常
@FunctionalInterface interface DspSupplier<T> { /** * Gets a result. * * @return a result */ T get() throws Exception; }
因而 retry 方法就變成了下面這樣子
public class RetryUtil { public static <T> T retry(int maxRetryCount, DspSupplier<T> supplier, BiFunction<T, Exception, Boolean> consumer) throws Exception{ // 省略... }
使用了自定義的 Supplier 後,調用方就沒有 「Unhandled exception」 了
咱們平時再開發的過程當中,能夠嘗試去利用函數式接口去實現一些邏輯的抽取,作成一個工具類,供你們使用,簡化人力,也是對本身編碼能力的一個提高。
上面的案例比較簡單,但麻雀雖小,五臟俱全,也是一個不錯的體驗 歡迎關注公衆號 【天天曬白牙】,獲取最新文章,咱們一塊兒交流,共同進步!