Java异常处理

来源:互联网 发布:中国种植网域名交易 编辑:程序博客网 时间:2024/06/05 15:32

Java异常对性能损耗很大,所以我们要少用异常?

不知道从哪里听来的,关于java很多人都会说java效率低,或者java异常处理非常不好等等一系列的问题.
本章主要讨论java的异常,以及异常处理方式.所以我们先来讨论下java处理异常时,时间都花在了哪里.
下面用4个代码片段,并通过比较执行时间来分析java中的异常.

这里写图片描述
这里写图片描述

  1. 以上时间单位是纳秒.(1秒等于10的9次方纳秒)
  2. A与B的执行时间很相近,A用时0.36秒 B用时0.359秒.从中我们得知,捕获异常对于性能而言是几乎没有性能损耗的.
  3. B用时是0.359秒,C用时是1.43秒,从中可以看出抛出异常将会有很大的性能损失.
    本例中平均每次抛出异常将耗时(1437373638-359250837)/1000000=1078.122纳秒
  4. C用时1.43秒,D用时0.44秒(与A和B同一个数量级).同样的抛出异常为什么区别这么大?下面看一看MyException你就会明白了.
    这里写图片描述

从上我们得知:
* try…catch… 对于性能而言几乎是不损耗的.
* 所谓的异常效率低是因为抛出异常导致的.因为在抛出异常时会调用fillInStackTrace方法填充堆栈信息,所以就多花了点时间,但是这是正常的.
* 尽管抛出异常会花费一定的时间,但是真正的业务逻辑中你会像本例中抛出一百万个异常吗?如果感兴趣你可以算算平均每抛出一个异常耗费多长时间.
* 从上我们明白了异常处理大部分时间都耗在哪里了,那么抛出的异常我们如何处理呢?

如何处理异常

我经常听到下面这样的话.
* 捕获到异常之后要打印异常信息.
* 自己能处理的就自己处理,自己不能处理的抛到上层让调用方法处理.
PS: 虽然不知道上面什么意思,打算大家都这么说.下面我就说说我对于异常处理.

1.catch块中一定要做点什么.

    try {        // 处理业务逻辑    } catch (Exception e) {    }
  • 只有在你非常确定的情况下才能这么写,否则请不要掩盖问题.
  • 这么写意味着异常不会显示在控制台上,你将发现不了任何问题.
  • 请考虑运维同胞的感受,否则他们会懵B的.我想也许出了问题但是看不到问题在哪里,他们会想杀了这个写代码的家伙.

2.请维护异常链的完整性.

    try {        int i = 1/0;    } catch (Exception e) {        e.printStackTrace();        throw new RuntimeException("处理业务A异常, 异常原因 : " + e.getMessage() );    }
  • 也许我们经常会看到上面那样的书写方式.先打印异常,然后抛出异常并添加一点自己的信息描述.
  • 看出来好像也没啥问题啊?不挺正常的吗?我们来看看控制台的异常信息.
    这里写图片描述
  • 异常信息一共4行,前两行是打印的,后两行是抛出的之后虚拟机捕获到然后打印的.
  • 从中我们知道了,异常不停往上抛,如果虚拟机捕获到了,那么将会将异常打印出来.
  • 我们在看看下面一段代码
    这里写图片描述
    • 对比两张控制台的异常信息你会发现,下面的异常很容易理解.处理业务有问题,问题原因Caused by:XXX
    • 而上面的处理方式把异常链断开了.导致异常断断续续的,并不是很容易理解.同时还重复打印了相同异常描述/ by zero
    • 下面的方式维护了异常链的完整性,所以你可以很清楚的看明白问题出在哪里,由谁引起的.
    • 但是你会发现,下面的异常信息有6行,但是第一和第二行和第五和第六行一样的.所以我们可以这么做
      这里写图片描述
  • 从中我们可以发现 抛出异常时,请把捕获的异常当作参数传递下去从而维护异常链完整性.
  • 如果你在catch中抛出异常了,那么就别打印了.不然异常信息会重复.

3.如何抛出异常

  • 异常产生的原因很多,但是90%以上的原因都是因为输入参数不合法导致的.
  • 如果是jdk抛出的异常(例如空指针或者解析问题)这种只需要我们捕获并处理就行了.
  • 有时候我们需要自己抛出异常.例如
    这里写图片描述
  • 但是这个显示是RuntimeException,并不是和符合情景.我们是参数无效.所以应该抛出IllegalArgumentException异常.
    这里写图片描述
  • Spring有个工具类,org.springframework.util.Assert.断言工具类
    这里写图片描述

    • 该工具类表示,程序运行到该行,需要具有某种状态.例如某个参数应该是这样,或者什么什么预期是这样的.
      如果不是这样,那么将抛出异常.
    • 例如上面表示,运行到这行,这个参数是非空的.但是却发现他没有值,与预期的相差很大,所以就异常了.
  • 从中我们可以发现,抛出异常时,异常最好能够表示属于什么异常.例如空指针是NullPointerException.

  • 另外,善用工具类对提高代码的水平也很有帮助,同时也增加了代码健壮性.避免动不动就抛出异常.

异常的分类

  • 异常有两种,一种是运行时异常(非检查) 一种是检查异常.
  • 非检测异常
    • 书写时,可能抛出异常,但是不提示你.例如Long.valueOf().该方法声明抛出异常.但是你不用显示try…catch…
    • 例如RuntimeException
  • 检查异常
    • 强制你抛出或者try…catch…的异常.例如Exception
0 0
原创粉丝点击