Java 异常处理的十个建议(非常有用,建议收藏!!)

各位程序猿平常敲代码的时候是不是明明有时候没错但它就是报错呢,今天我就给大家整理了十个经常会报错的异常处理建议,希望对大家有帮助!

一、尽量不要使用e.printStackTrace(),而是使用log打印。

反例:

try{

  // do what you want 

}catch(Exception e){

  e.printStackTrace();

}

正例:

try{

  // do what you want 

}catch(Exception e){

  log.info("你的程序有异常啦,{}",e);

}

理由:

1.printStackTrace()打印出的堆栈日志跟业务代码日志是交错混合在一起的,排查异常日志不太方便。

2.e.printStackTrace()语句产生的字符串记录的是堆栈信息,如果信息太长太多,字符串常量池所在的内存块没有空间了,即内存满了,那么,用户的请求就卡住啦~

二、catch了异常,但是没有打印出具体的exception,无法更好定位问题

反例:

try{

  // do what you want 

}catch(Exception e){

  log.info("你的程序有异常啦");

}

正例:

try{

  // do what you want 

}catch(Exception e){

  log.info("你的程序有异常啦,{}",e);

}

理由:

反例中,并没有把exception出来,到时候排查问题就不好查了啦,到底是SQl写错的异常还是IO异常,还是其他呢?所以应该把exception打印到日志中哦~

三、不要用一个Exception捕捉所有可能的异常

反例:

public void test(){

    try{

        //…抛出 IOException 的代码调用

        //…抛出 SQLException 的代码调用

    }catch(Exception e){

        //用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息哦

        log.info(“Exception in test,exception:{}”, e);

    }

}

正例:

public void test(){

    try{

        //…抛出 IOException 的代码调用

        //…抛出 SQLException 的代码调用

    }catch(IOException e){

        //仅仅捕捉 IOException

        log.info(“IOException in test,exception:{}”, e);

    }catch(SQLException e){

        //仅仅捕捉 SQLException

        log.info(“SQLException in test,exception:{}”, e);

    }

}

理由:

用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息哦

四、记得使用finally关闭流资源或者直接使用try-with-resource

反例:

FileInputStream fdIn = null;

try {

    fdIn = new FileInputStream(new File("/jay.txt"));

    //在这里关闭流资源?有没有问题呢?如果发生异常了呢?

    fdIn.close();

} catch (FileNotFoundException e) {

    log.error(e);

} catch (IOException e) {

    log.error(e);

}

正例1:

需要使用finally关闭流资源,如下

FileInputStream fdIn = null;

try {

    fdIn = new FileInputStream(new File("/jay.txt"));

} catch (FileNotFoundException e) {

    log.error(e);

} catch (IOException e) {

    log.error(e);

}finally {

    try {

        if (fdIn != null) {

            fdIn.close();

        }

    } catch (IOException e) {

        log.error(e);

    }

}

正例2:

当然,也可以使用JDK7的新特性try-with-resource来处理,它是Java7提供的一个新功能,它用于自动资源管理。

资源是指在程序用完了之后必须要关闭的对象。

try-with-resources保证了每个声明了的资源在语句结束的时候会被关闭

什么样的对象才能当做资源使用呢?只要实现了java.lang.AutoCloseable接口或者java.io.Closeable接口的对象,都OK。

try (FileInputStream inputStream = new FileInputStream(new File("jay.txt")) {

    // use resources 

} catch (FileNotFoundException e) {

    log.error(e);

} catch (IOException e) {

    log.error(e);

}

理由:

如果不使用finally或者try-with-resource,当程序发生异常,IO资源流没关闭,那么这个IO资源就会被他一直占着,这样别人就没有办法用了,这就造成资源浪费。

五、捕获异常与抛出异常必须是完全匹配,或者捕获异常是抛异常的父类

反例:

//BizException 是 Exception 的子类

public class BizException extends Exception {}

//抛出父类Exception

public static void test() throws Exception {}

try {

    test(); //编译错误

} catch (BizException e) { //捕获异常子类是没法匹配的哦

    log.error(e);

}

正例:

//抛出子类Exception

public static void test() throws BizException {}

try {

    test();

} catch (Exception e) {

    log.error(e);

}

六、捕获到的异常,不能忽略它,至少打点日志吧

反例:

public static void testIgnoreException() throws Exception {

    try {     

        // 搞事情

    } catch (Exception e) {    //一般不会有这个异常


    }

}

正例:

public static void testIgnoreException() {

    try {

        // 搞事情

    } catch (Exception e) {    //一般不会有这个异常

        log.error("这个异常不应该在这里出现的,{}",e);

    }

}

理由:

虽然一个正常情况都不会发生的异常,但是如果你捕获到它,就不要忽略呀,至少打个日志吧~

七、注意异常对你的代码层次结构的侵染(早发现早处理)

反例:

public UserInfo queryUserInfoByUserId(Long userid) throw SQLException {

    //根据用户Id查询数据库

}

正例:

public UserInfo queryUserInfoByUserId(Long userid) {

    try{

        //根据用户Id查询数据库

    }catch(SQLException e){

        log.error("查询数据库异常啦,{}",e);

    }finally{

        //关闭连接,清理资源

    }

}

理由:

我们的项目,一般都会把代码分 Action、Service、Dao 等不同的层次结构,如果你是DAO层处理的异常,尽早处理吧,如果往上throw SQLException,上层代码就还是要try catch处理了,这就污染了你的代码~

八、自定义封装异常,不要丢弃原始异常的信息Throwable cause

我们常常会想要在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这被称为异常链。公司的框架提供统一异常处理就用到异常链,我们自定义封装异常,不要丢弃原始异常的信息,否则排查问题就头疼啦

反例:

public class TestChainException {

    public void readFile() throws MyException{

        try {

            InputStream is = new FileInputStream("jay.txt");

            Scanner in = new Scanner(is);

            while (in.hasNext()) {

                System.out.println(in.next());

            }

        } catch (FileNotFoundException e) {

            //e 保存异常信息

            throw new MyException("文件在哪里呢");

        }

    }

    public void invokeReadFile() throws MyException{

        try {

            readFile();

        } catch (MyException e) {

            //e 保存异常信息

            throw new MyException("文件找不到");

        }

    }

    public static void main(String[] args) {

        TestChainException t = new TestChainException();

        try {

            t.invokeReadFile();

        } catch (MyException e) {

            e.printStackTrace();

        }

    }

}

//MyException 构造器

public MyException(String message) {

        super(message);

    }

运行结果呢就是,没有了Throwable cause,不好排查是什么异常了

正例:

public class TestChainException {

    public void readFile() throws MyException{

        try {

            InputStream is = new FileInputStream("jay.txt");

            Scanner in = new Scanner(is);

            while (in.hasNext()) {

                System.out.println(in.next());

            }

        } catch (FileNotFoundException e) {

            //e 保存异常信息

            throw new MyException("文件在哪里呢", e);

        }

    }

    public void invokeReadFile() throws MyException{

        try {

            readFile();

        } catch (MyException e) {

            //e 保存异常信息

            throw new MyException("文件找不到", e);

        }

    }

    public static void main(String[] args) {

        TestChainException t = new TestChainException();

        try {

            t.invokeReadFile();

        } catch (MyException e) {

            e.printStackTrace();

        }

    }

}

//MyException 构造器

public MyException(String message, Throwable cause) {

        super(message, cause);

    }

这边就是系统找不到指定文件,这样就知道错在哪了。

九、运行时异常RuntimeException ,不应该通过catch 的方式来处理,而是先预检查,比如:NullPointerException处理

反例:

try {

  obj.method()

} catch (NullPointerException e) {

...

}

正例:

if (obj != null){

  ...

}

十、注意异常匹配的顺序,优先捕获具体的异常

注意异常的匹配顺序,因为只有第一个匹配到异常的catch块才会被执行。如果你希望看到,是NumberFormatException异常,就抛出NumberFormatException,如果是IllegalArgumentException就抛出IllegalArgumentException。

反例:

try {

    doSomething("test exception");

} catch (IllegalArgumentException e) {     

    log.error(e);

} catch (NumberFormatException e) {

    log.error(e);

}

正例:

try {

    doSomething("test exception");

} catch (NumberFormatException e) {     

    log.error(e);

} catch (IllegalArgumentException e) {

    log.error(e);

}

理由:

因为NumberFormatException是IllegalArgumentException的子类,反例中,不管是哪个异常,都会匹配到IllegalArgumentException,就不会再往下执行啦,因此不知道是否是NumberFormatException。所以需要优先捕获具体的异常,把NumberFormatException放前面~

对Java有兴趣的可以私我或者评论交流!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容