把"重試"抽象出來作個工具類吧

背景介紹

咱們在工做中不免會寫一些重複性的代碼,因此須要咱們具有必定的抽象能力,好比把共同的邏輯抽取到抽象類中,也能夠經過一些工具類來避免冗餘代碼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」 了

總結

咱們平時再開發的過程當中,能夠嘗試去利用函數式接口去實現一些邏輯的抽取,作成一個工具類,供你們使用,簡化人力,也是對本身編碼能力的一個提高。

上面的案例比較簡單,但麻雀雖小,五臟俱全,也是一個不錯的體驗 歡迎關注公衆號 【天天曬白牙】,獲取最新文章,咱們一塊兒交流,共同進步!

相關文章
相關標籤/搜索