zoukankan      html  css  js  c++  java
  • Java异常实践事项

         在大学项目开发中, 你有没发现自己做的项目总是出现bug,不仅仅出现bug,而且很难根据异常信息找到异常源。我当时也是非常懊恼, 可怕的是不知道怎么维护... 软件Java异常需要理解基础的知识, 在实战中较好的处理异常。Java异常基础知识tryCatchFinally语句块  本节总结Java异常在实践中的相关事项

    1、 在Finally中清理资源或者使用Try-With-Resource语句

          不要在try中关闭资源、因为一旦发生异常, 将无法正常关闭资源。以下代码给出二种处理方案, Finally关闭资源、Try-With-Resource(JDK1.7出现)

    /** 写数据
         * */
        public static void writeFile(File file) {
            OutputStream os=null;
            try {
                 os=new FileOutputStream(file);
                 String str=new String("hello gay!");
                  //     os.write(str); 不编码--错误
                 os.write(str.getBytes());// 按照默认的GBK编码
                 os.write(5);
                 os.flush();
            } catch (Exception e) {
                e.printStackTrace();
                
            }finally{
               try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            }
    /** 写数据
         * */
        public static void writeFile(File file) {
    
                   // 它将在try被执行后自动关闭,或者处理一个异常。
            try(OutputStream os=new FileOutputStream(file)) {
                 String str=new String("hello gay!");
                       os.write(str.getBytes());// 按照默认的GBK编码
                 os.write(5);
            } catch (Exception e) {
                e.printStackTrace();
                
            }
            
            
        }

    2、 给出准确的异常处理信息

          尽量能更好地描述你的异常处理信息,比如用 NumberFormatException 代替 IllegalArgumentException ,避免抛出一个不具体的异常。catch语句块中子类在前、父类在后。

    public void doNotDoThis() throws Exception {
       }
    public void doThis() throws NumberFormatException {
      
    }

    3、记录自定义异常

           为了给调用人员和维护者更清晰的异常信息、请确保在Javadoc中添加一个@throws 声明,并描述可能导致的异常情况

    /**
     * This method does something extremely useful ...
     * @throws MyBusinessException if ... happens
     */
    public void doSome() throws MyBusinessException {
        ...
    }

    4、记录异常信息

          用1-2个简短的句子解释异常的原因、使用日志文件记录

    try {
        new Long("abc");
    } catch (NumberFormatException e) {
        log.error(new Exception("xxx",e));
    }

    5、最先捕获特定的异常

             把特点的、已知的异常先捕获。catch块中只有第一个匹配到异常的catch语句才会被执行,所以,如果你最先发现IllegalArgumentException,你将永远不会到达catch里处理更具体的NumberFormatException,因为它是IllegalArgumentException的一个子类。所以要首先捕获特定的异常类,并在末尾添加一些处理不是很具体异常的catch语句。子类应该在前面、父类在后面。最后一个catch可以写Exception。

    public void catchMostSpecificExceptionFirst() {
        try {
            doSomething("A message");
        } catch (NumberFormatException e) {
            log.error(e);
        } catch (IllegalArgumentException e) {
            log.error(e)
        } catch(Exception){
            //使用Exception捕获不确定的、模糊的异常
          log.error(e);
        }
    }

    6. 不要在catch中使用Throwable

        因为所有的Exception(包括Error)都是Throwtable的子类。Error是JVM异常,我们无法预计和修改。Throwable也不够仔细。

    public void doNotCatchThrowable() {
        try {
            // do something
        } catch (Throwable t) {
            // don't do this!
        }
    }

    7、不要捕获和抛出异常

         或许这样看起来很nice,当它发生时记录一个异常,然后重新抛出它,以便调用者能够适当地处理它。但是这样会同时打印日志信息和异常信息。

    如果你需要添加额外的信息,应该捕获异常并将其包装在一个自定义的信息中。但要确保遵循下面的第8条异常链化。

    try {
        new Long("xyz");
    } catch (NumberFormatException e) {
        log.error(e);
        throw e;
    }
    17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"
    Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Long.parseLong(Long.java:589)
    at java.lang.Long.(Long.java:965)
    at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
    at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)

    可能这样说不太清楚,举个例子假如main调用B函数、在B中调用A函数、A中发生异常, 而我们把异常交给调用者处理(main中);应该这样:A中抛出异常、B链化抛出、main中捕获并且处理、记录。

    public static void main(String[] args)
    {
        
        System.out.println("请输入2个加数");
        int result;
        try
        {
            result = add();
            System.out.println("结果:"+result);
        } catch (Exception e){
        //1、记录
         log.error(e);
        //2、处理,比如打印;
            e.printStackTrace();
        }
    }
    //获取输入的2个整数返回
    private static List<Integer> getInputNumbers()
    {
        List<Integer> nums = new ArrayList<>();
        Scanner scan = new Scanner(System.in);
        try {
            int num1 = scan.nextInt();
            int num2 = scan.nextInt();
            nums.add(new Integer(num1));
            nums.add(new Integer(num2));
        }catch(InputMismatchException immExp){
            throw immExp;
        }finally {
            scan.close();
        }
        return nums;
    }
    
    //执行加法计算
    private static int add() throws Exception
    {
        int result;
        try {
            List<Integer> nums =getInputNumbers();
            result = nums.get(0)  + nums.get(1);
        }catch(InputMismatchException immExp){
            throw new Exception("计算失败",immExp);  /////////////////////////////链化:以一个异常对象为参数构造新的异常对象。
        }
        return  result;
    }

    8 、链化--包装异常

           异常的链化可以将多个模块的异常串联起来,使得异常信息不会丢失。

         异常链化:以一个异常对象为参数构造新的异常对象。新的异对象将包含先前异常的信息。这项技术主要是异常类的一个带Throwable参数的函数来实现的。这个当做参数的异常,我们叫他根源异常(cause)。 

    public static void main(String[] args)
    {
        
        System.out.println("请输入2个加数");
        int result;
        try
        {
            result = add();
            System.out.println("结果:"+result);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
    //获取输入的2个整数返回
    private static List<Integer> getInputNumbers()
    {
        List<Integer> nums = new ArrayList<>();
        Scanner scan = new Scanner(System.in);
        try {
            int num1 = scan.nextInt();
            int num2 = scan.nextInt();
            nums.add(new Integer(num1));
            nums.add(new Integer(num2));
        }catch(InputMismatchException immExp){
            throw immExp;
        }finally {
            scan.close();
        }
        return nums;
    }
    
    //执行加法计算
    private static int add() throws Exception
    {
        int result;
        try {
            List<Integer> nums =getInputNumbers();
            result = nums.get(0)  + nums.get(1);
        }catch(InputMismatchException immExp){
            throw new Exception("计算失败",immExp);  /////////////////////////////链化:以一个异常对象为参数构造新的异常对象。
        }
        return  result;
    }
    
    /*
    请输入2个加数
    r 1
    java.lang.Exception: 计算失败
        at practise.ExceptionTest.add(ExceptionTest.java:53)
        at practise.ExceptionTest.main(ExceptionTest.java:18)
    Caused by: java.util.InputMismatchException
        at java.util.Scanner.throwFor(Scanner.java:864)
        at java.util.Scanner.next(Scanner.java:1485)
        at java.util.Scanner.nextInt(Scanner.java:2117)
        at java.util.Scanner.nextInt(Scanner.java:2076)
        at practise.ExceptionTest.getInputNumbers(ExceptionTest.java:30)
        at practise.ExceptionTest.add(ExceptionTest.java:48)
        ... 1 more
    
    */

    附加: finally块的细节 

    • 不要在fianlly中使用return。
    • 不要在finally中抛出异常。
    • 减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的。
    • 将尽量将所有的return写在函数的最后面,而不是try ... catch ... finally中。
  • 相关阅读:
    C#dll中无法找到c++dll中函数的入口
    C#委托及事件处理机制浅析
    lib和dll的例子
    C#中自定义消息,与MFc对比
    MFC消息响应机制 q
    MFC中消息响应机制
    C# 消息处理机制及自定义过滤方式
    c++中__declspec用法总结
    C++中使用接口
    C# 位域[flags] 转
  • 原文地址:https://www.cnblogs.com/achievement-active/p/9310975.html
Copyright © 2011-2022 走看看