日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

前言

我們經(jīng)常在很多項(xiàng)目里面看到用異常來處理業(yè)務(wù)邏輯,發(fā)現(xiàn)不符合預(yù)期直接拋出異常,然后在最外面捕獲異常統(tǒng)一處理,這樣使用非常方便。

但是又有很多文章寫著異常處理性能,所以不建議使用異常來做流程控制。甚至在阿里巴巴開發(fā)手冊(cè)里面明確說明了,不要用來做流程控制。

 

那么問題來了:

究竟能不能用異常來做流程控制?效率低是低多少?看完這一篇文章你就知道了。

開始測(cè)試

先做最簡(jiǎn)單的測(cè)試

我們循環(huán)10萬次,然后棧有5層,然后輸出返回結(jié)果。

private static final int RUN_COUNT = 10 * 10000;

    /**
     * 測(cè)試異常耗時(shí)
     * 輸出異常堆棧&信息
     */
    @Test
    public void printStack() {
        long start1 = System.currentTimeMillis();
        for (int i = 0; i < RUN_COUNT; i++) {
            log.info(Storey1.test());
        }

        long start2 = System.currentTimeMillis();
        for (int i = 0; i < RUN_COUNT; i++) {
            try {
                Storey1.testException();
            } catch (Exception e) {
                log.info(e.getMessage(), e);
            }
        }
        long end = System.currentTimeMillis();
        log.info("普通返回耗時(shí):{},異常返回耗時(shí):{}", start2 - start1, end - start1);
    }
    public static class Storey1 {
        public static String test() {
            return Storey2.test();
        }

        public static String testException() {
            return Storey2.testException();
        }
    }

    public static class Storey2 {
        public static String test() {
            return Storey3.test();
        }

        public static String testException() {
            return Storey3.testException();
        }
    }

    public static class Storey3 {
        public static String test() {
            return Storey4.test();
        }

        public static String testException() {
            return Storey4.testException();
        }
    }

    public static class Storey4 {
        public static String test() {
            return Storey5.test();
        }

        public static String testException() {
            return Storey5.testException();
        }
    }

    public static class Storey5 {
        public static String test() {
            return Integer.toString(count++);
        }

        public static String testException() {
            throw new CustomException(Integer.toString(count++));
        }
    }


    public static class CustomException extends RuntimeException {

        public CustomException(String message) {
            super(message);
        }

    }

結(jié)果差別很大,普通返回只要2137毫秒,而異常卻要75026毫秒,幾十倍的差距。

15:07:59.648 [main] INFO com.alibaba.easytools.test.temp.exception.ExceptionTest - 普通返回耗時(shí):2137,異常返回耗時(shí):75026

不輸出堆棧信息

聰明的同學(xué)不難發(fā)現(xiàn),上面有個(gè)變量沒控制住,就是使用異常的情況下,輸出了堆棧信息,那我們關(guān)閉堆棧輸出試試。會(huì)不會(huì)是輸出的堆棧信息導(dǎo)致的慢呢?

  /**
     * 測(cè)試異常耗時(shí)
     * 僅僅輸出信息
     */
    @Test
    public void print() {
        long start1 = System.currentTimeMillis();
        for (int i = 0; i < RUN_COUNT; i++) {
            log.info(Storey1.test());
        }

        long start2 = System.currentTimeMillis();
        for (int i = 0; i < RUN_COUNT; i++) {
            try {
                Storey1.testException();
            } catch (Exception e) {
                log.info(e.getMessage());
            }
        }
        long end = System.currentTimeMillis();
        log.info("普通返回耗時(shí):{},異常返回耗時(shí):{}", start2 - start1, end - start1);
    }

結(jié)果發(fā)現(xiàn)普通返回是2053毫秒,而異常卻要4380毫秒,發(fā)現(xiàn)差距瞬間變小了。

15:43:54.260 [main] INFO com.alibaba.easytools.test.temp.exception.ExceptionTest - 普通返回耗時(shí):2053,異常返回耗時(shí):4380

不輸出任何信息

顯然我們發(fā)現(xiàn),關(guān)閉了日志輸出對(duì)執(zhí)行時(shí)間影像很大,那我們關(guān)閉了日志輸出會(huì)有什么效果了呢?

    /**
     * 測(cè)試異常耗時(shí)
     * 不輸出信息
     */
    @Test
    public void noPrint() {
        long start1 = System.currentTimeMillis();
        for (int i = 0; i < RUN_COUNT; i++) {
            Storey1.test();
        }

        long start2 = System.currentTimeMillis();
        for (int i = 0; i < RUN_COUNT; i++) {
            try {
                Storey1.testException();
            } catch (Exception e) {
            }
        }
        long end = System.currentTimeMillis();
        log.info("普通返回耗時(shí):{},異常返回耗時(shí):{}", start2 - start1, end - start1);
    }

結(jié)果發(fā)現(xiàn)普通返回是58毫秒,而異常卻要719毫秒,看來性能實(shí)際差距就是十幾倍。

15:47:55.901 [main] INFO com.alibaba.easytools.test.temp.exception.ExceptionTest - 普通返回耗時(shí):58,異常返回耗時(shí):719

關(guān)閉堆棧

在處理異常的時(shí)候,很多時(shí)間在封裝異常堆棧,那有沒有辦法可以不要封裝呢?

仔細(xì)研究異常類發(fā)現(xiàn),異常類有個(gè)參數(shù)`writableStackTrace` 可以讓異常不去封裝堆棧信息。

public class RuntimeException extends Exception {

    /**
     * Constructs a new runtime exception with the specified detail
     * message, cause, suppression enabled or disabled, and writable
     * stack trace enabled or disabled.
     *
     * @param  message the detail message.
     * @param cause the cause.  (A {@code null} value is permitted,
     * and indicates that the cause is nonexistent or unknown.)
     * @param enableSuppression whether or not suppression is enabled
     *                          or disabled
     * @param writableStackTrace whether or not the stack trace should
     *                           be writable
     *
     * @since 1.7
     */
    protected RuntimeException(String message, Throwable cause,
                               boolean enableSuppression,
                               boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

我們把拋異常的時(shí)候不去封裝異常信息

    /**
     * 測(cè)試異常耗時(shí)
     * 關(guān)閉堆棧 并且不打印
     */
    @Test
    public void noPrintCloseStackTrace() {
        long start1 = System.currentTimeMillis();
        for (int i = 0; i < RUN_COUNT; i++) {
            Storey1.test();
        }

        long start2 = System.currentTimeMillis();
        for (int i = 0; i < RUN_COUNT; i++) {
            try {
                Storey1.testException();
            } catch (Exception e) {
            }
        }
        long end = System.currentTimeMillis();
        log.info("普通返回耗時(shí):{},異常返回耗時(shí):{}", start2 - start1, end - start1);
    }

    public static class Storey5 {
        public static String test() {
            return Integer.toString(count++);
        }

        public static String testException() {            throw new CustomException(Integer.toString(count++), null, false, false);
        }
    }

    public static class CustomException extends RuntimeException {

        public CustomException(String message) {
            super(message);
        }

        public CustomException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
            super(message, cause, enableSuppression, writableStackTrace);
        }
    }

結(jié)果發(fā)現(xiàn)普通返回是31毫秒,而異常卻要62毫秒,差距也沒有想象中的大了。差不多是2倍左右。

15:54:26.984 [main] INFO com.alibaba.easytools.test.temp.exception.ExceptionTest - 普通返回耗時(shí):31,異常返回耗時(shí):62

最終結(jié)果

我們來看下最終對(duì)比結(jié)論

 

普通

異常

普通輸出日志,異常輸出堆棧

2137

75026

普通輸出日志,異常僅輸出日志

2053

4380

都不輸出日志

58

719

關(guān)閉堆棧

31

62

結(jié)論

所以我們可以總結(jié)出以下結(jié)論

  • 日志輸出堆棧非常耗時(shí)
  • 哪怕日志只是輸出業(yè)務(wù)邏輯,耗時(shí)和業(yè)務(wù)處理也不是一個(gè)時(shí)間維度的
  • 排出日志影響,封裝堆棧非常耗時(shí)
  • 關(guān)閉堆棧以后耗時(shí)相差不大,大概1萬次相差3毫秒

三種方式優(yōu)缺點(diǎn)總結(jié)下:

 

優(yōu)點(diǎn)

缺點(diǎn)

普通

  • 最快速
  • 嵌套深了,或者有返回值的情況下代碼會(huì)比較丑陋
  • 如果打印了請(qǐng)求日志,多個(gè)地方返回相同值,不好排查

關(guān)閉堆棧的異常

  • 相對(duì)速度還行
  • 代碼相對(duì)書寫比較方便
  • 有時(shí)候不打印堆棧多個(gè)地方返回相同值,不好排查

不關(guān)閉堆棧的異常

  • 代碼相對(duì)書寫比較方便
  • 能打印整個(gè)堆棧信息,非常容易定位問題
  • 速度慢

如果我們的并發(fā)沒有大到必須關(guān)閉日志這種情況下,實(shí)際上來說異常來控制流程問題不大,影響微乎其微,所以還是怎么方便怎么來。

當(dāng)然如果項(xiàng)目并發(fā)超級(jí)高,高到單機(jī)1萬次請(qǐng)求要省3毫秒的情況下,建議還是用返回去控制業(yè)務(wù)流程。

分享到:
標(biāo)簽:Java
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定