zoukankan      html  css  js  c++  java
  • Java:如何正确地使用异常详解

    概述:

      Java中的异常机制是一个好东西。不过好东西也要正确地使用才行,不然就会让我们错误地认识它。在错误地认识状况下,就会错误地使用。这样就成了一个恶性地循环了。这不是我们愿意看到的。不要以为我们已经可以很好地使用异常了,下面就针对部分问题作一个讲解。这部分的问题中,有一些是来自《Effective Java》这本书中,有一部分是来自本人平时开发过程中遇到的。


    本文链接:http://blog.csdn.net/lemon_tree12138/article/details/50474230 -- Coding-Naga
                                                                     --转载请注明出处

    1.是throw还是try-catch

      这个是一个对刚接触编程开发的人来说,经常面临但又选择不好的问题。

      由于我们开发的项目可不是像写Demo一样轻松,这里可能会有很多层次结构。我们要在具体哪一层的什么位置是使用try-catch这个异常呢,还是把异常throw到上一层呢?这里,我们首先要知道一件事,那就是try-catch和throw分别会发生什么情况呢?

    try-catch: 捕获一个异常情况,并中止try块中的后续操作。且不会再向上抛出异常了。

    throw: 当使用throw抛出一个异常时,当前的执行块(方法)会结束后续的执行。相当于一个return操作,并保证了上层在调用的时候可以捕获到这个异常,并做相应处理。

    Demo示例如下:

    public class ExceptionClient {
    
        public static void main(String[] args) {
            ExceptionClient client = new ExceptionClient();
            
            client.showInfo();
        }
        
        private void showInfo() {
            try {
                System.out.println("first info");
                testException();
                System.out.println("second info");
            } catch (Exception e) {
                System.err.println(e);
            }
            
            System.out.println("outside info");
        }
        
        private void testException() throws AException {
            boolean f = true;
            if (f) {
                throw new AException("AException");
            }
            
            System.out.println("f is false.");
        }
    }
    
      按照上面对try-catch和throw的分析,可以知道,showInfo方法try块中的第二句话是不打印的,而testException方法的最后一句也是不打印的。结果如下:

    图-1 try-catch测试结果

    2.是使用受检的异常还是非受检的异常

      首先我们要了解什么是受检异常和非受检异常,不过这里顾名思义,受检即接受检查。由于目前的IDE很是智能,当我们在使用受检异常而未try-catch这个异常时,IDE会给出错误提示。如下:


    图-2 IDE对受检异常的检查

      而非受检异常则不会被IDE识别。还有一点,因为前面说到IDE会检测到受检异常,所以,这里如果我们强行运行此代码,是通不过编译的,非受检异常则不会。

      好了,说明了受检异常和非受检异常在使用过程中的区别。现在就来说说怎么创建这些不同的异常吧。

      当我们要编写自定义的受检异常A.java时,A的class需要继承Exception,而非受检异常B.java则是继承RuntimeException

      由于受检异常会在使用的过程,强行限制开发人员去try-catch。而在try-catch此异常的时候,开发人员则可以对此异常进行修正并重新之前的操作(即恢复)。在RuntimeException中则没有这样的限制。所以,当我们试图告诉调用者,当前的异常是可以被修复,并允许重新去调用的时候,我们就使用受检的异常,当我们认为这是一个程序错误的时候,则需要使用非受检异常。

      可能对在何时使用受检异常或非受检异常有了一些基本认识,然后你可能会问这样的一个问题:我们不是还有一个Error么,那么错误(Error)和异常有什么区别呢?下面就列举了这两者之间的区别(点击查看参考来源):

    Exception:
    1.可以是可被控制(checked) 或不可控制的(unchecked)。
    2.表示一个由程序员导致的错误。
    3.应该在应用程序级被处理。
    Error:
    1.总是不可控制的(unchecked)。
    2.经常用来用于表示系统错误或低层资源的错误。
    3.如何可能的话,应该在系统级被捕捉。


    3.只针对不正确的条件才使用异常

      关于这一点,首先我们应该了解的是Java在进行异常检查时消耗的系统资源,要比普通的程序调用高。那么,如果我们的程序在不停地进行异常检查,就会对程序整个的性能产生不小的影响。我们可以从一个小例子中看出这一点。如下:

    假设现有10000000个元素的List,我们要对此List进行遍历,有三种方式,分别如下:

    第一种:对每一种情况进行异常检查

    private void call_1(List<Integer> list) {
            long t = System.currentTimeMillis();
            try {
                int index = 0;
                while(true) {
                    list.get(index++);
                } 
            } catch (IndexOutOfBoundsException e) {
                LogUtils.printTimeUsed("不针对检查异常", t);
            }
        }

    第二种:只对错误的情况进行异常检查

    private void call_2(List<Integer> list) {
            long t = System.currentTimeMillis();
            t = System.currentTimeMillis();
            int size = list.size();
            int index = 0;
            while(true) {
                if (index >= size) {
                    try {
                        list.get(index++);
                    } catch (IndexOutOfBoundsException e) {
                        LogUtils.printTimeUsed("针对性检查异常", t);
                        break;
                    }
                }
                list.get(index++);
            }
        }

    第三种:普通的循环遍历

    private void call_3(List<Integer> list) {
            long t = System.currentTimeMillis();
            t = System.currentTimeMillis();
            int size = list.size();
            int index = 0;
            for (index = 0; index < size; index++) {
                list.get(index++);
            }
            
            LogUtils.printTimeUsed("循环遍历", t);
        }

    测试结果:


    图-3 不同异常检查方式遍历List

      从上面的测试结果中,我们可以看到不针对地检查异常(盲目地检查异常),比有针对性地检查异常性能上低了不少。所以,我们在使用异常的时候,请格外谨慎。需要去避免一些不必要的异常检查,以优化我们的程序代码。


    Ref:

    Effective Java

  • 相关阅读:
    基于bootstrap实现收缩导航条
    js判断打开网站页面是PC端还是手机端
    vs2015调试sqlserver 存储过程
    C#计算当前日是第几周
    C#计算一年有多少周
    tcpdump命令的使用
    keepalived配置
    正则匹配中文
    git merge 和 git rebase详解
    systemd和sysv服务管理和配置
  • 原文地址:https://www.cnblogs.com/fengju/p/6336017.html
Copyright © 2011-2022 走看看