【译】11条Java异常处理的最佳实践

简介:

本文翻译自Top 11 Java Exception Best Practices


在之前关于Java异常的文章中,已经探讨过suppressed exceptionsJava Exceptions Tutorial 两个方面的内容。要想在实际项目中正确处理Java异常,你应该熟练掌握一些Java异常处理的最佳实践。

1240
Java 异常处理的最佳实践
  1. 不要 在catch语句块中压制异常

    public class ExceptionExample {
     public FileInputStream testMethod1(){
         File file = new File("test.txt");
         FileInputStream fileInputStream = null;
         try{
             fileInputStream = new FileInputStream(file);
             fileInputStream.read();
         }catch (IOException e){            
             return null;
         }
         return fileInputStream;
     }
     public static void main(String[] args){
         ExceptionExample instance1 = new ExceptionExample();
         instance1.testMethod1();
     }
    }

    在异常处理时进行异常压制是非常不好的编程习惯,上面的例子中,无论抛出什么异常都会被忽略,以至没有留下任何问题线索。如果在这一层次不知道如何处理异常,最好将异常重新抛出,由上层决定如何处理异常。

    public class ExceptionExample {
     public FileInputStream testMethod1() throws IOException{
         File file = new File("test.txt");
         FileInputStream fileInputStream = null;
         try{
             fileInputStream = new FileInputStream(file);
             fileInputStream.read();
         }catch (IOException e){            
             throw e;
         }
         return fileInputStream;
     }
     public static void main(String[] args) throws IOException{
         ExceptionExample instance1 = new ExceptionExample();
         instance1.testMethod1();
     }
    }
  2. 要在方法定义分句中定义具体的异常
    按照public FileInputStream testMethod1() throws Exception{这种写法,表示该方法会抛出所有受检查异常,这不是一个良好的编程习惯。在这种情况下,我们最好抛出足够具体的异常,以便调用者进行合适的捕获和处理,例如public FileInputStream testMethod1() throws IOException{

  3. 捕获具体的异常
    在调用其他模块时,最好捕获由该模块抛出的具体的异常。如果某个被调用模块抛出了多个异常,那么只捕获这些异常的父类是不好的编程习惯。
    例如,如果一个模块抛出FileNotFoundExceptionIOException,那么调用这个模块的代码最好写两个catch语句块分别捕获这两个异常,而不要只写一个捕获Exception的catch语句块。
    正确的写法如下:

    try {
    //some statements
    catch(FileNotFoundException e){
    //handle here
    }
    catch(IOException e){
    //handle here
    }

    你最好不要这么写:

    try {
    //some statements
    catch(Exception e){
    //handle here
    }
  4. 记得在finally语句块中释放资源
    当你在代码中建立了数据库连接、文件操作符或者其他需要被及时释放的系统资源,如果你没有及时释放这些资源,会影响到系统的性能。
    为了避免这种情况发生,可以使用Java 7的try(open the resources) {deal with resources}语句,如果你还是习惯这种老式写法,则可以按照如下方式写:

    finally {
         try {
             if (con != null) {
                 con.close();
             }
             if (stat != null) {
                 stat.close();
             }
         } catch (SQLException sqlee) {
             sqlee.printStackTrace();
         }
     }
  5. 异常会影响性能

    1240
    Performance


    异常处理的性能成本非常高,每个Java程序员在开发时都应牢记这句话。创建一个异常非常慢,抛出一个异常又会消耗1~5ms,当一个异常在应用的多个层级之间传递时,会拖累整个应用的性能。

    • 仅在异常情况下使用异常;
    • 在可恢复的异常情况下使用异常;

    尽管使用异常有利于Java开发,但是在应用中最好不要捕获太多的调用栈,因为在很多情况下都不需要打印调用栈就知道哪里出错了。因此,异常消息应该提供恰到好处的信息。

  6. 使用标准异常
    如果使用内建的异常可以解决问题,就不要定义自己的异常。Java API提供了上百种针对不同情况的异常类型,在开发中首先尽可能使用Java API提供的异常,如果标准的异常不能满足你的要求,这时候创建自己的定制异常。尽可能得使用标准异常有利于新加入的开发者看懂项目代码。

  7. 正确得包装异常类型
    当需要在应用重新抛出异常时,应该正确得包装原始异常,否则会丢失原始异常,例如下面的例子中:

    import java.io.IOException;
    public class HelloWorld{
      public static void main(String []args) throws Exception{
         try{
             throw new IOException("IOException");    
         }catch (IOException e){
             throw new ExampleException1("Example Exception and " + e.getMessage());
         }
    
      }
    }
    class ExampleException1 extends Exception{
     public ExampleException1(String s, Throwable t){
         super(s,t);
     }
     public ExampleException1(String s){
         super(s);
     }
    }

    这个程序的输出为:

    Exception in thread "main" ExampleException1: Example Exception and IOException                                                                                          
         at HelloWorld.main(HelloWorld.java:8)

    这里发现,IOException的调用栈已经丢失了,因为我们在catch语句块中没有正确包装IOException。若将catch语句块修改成下面这样,这可以发现原始异常的调用栈也被打印出来了。

    catch (IOException e){
             throw new ExampleException1("Example Exception",e);
         }

    这时候的输出如下:

    Exception in thread "main" ExampleException1: Example Exception                                                                                                
         at HelloWorld.main(HelloWorld.java:8)
    Caused by: java.io.IOException: IOException                                                                                                                              
         at HelloWorld.main(HelloWorld.java:6)
  8. 避免在finally语句块中抛出异常

    try {
    method();  //here throws first exception
    } finally {
    shutdown(); //If finally blockthrew any exception the first exception will be lost forever
    }

    在上面的这个代码片段中,finally代码块也可能再次抛出异常。如果同时抛出两个异常,则第一个异常的调用栈会丢失。在finally语句块中最好只做打印错误信息或者关闭资源等操作,避免在finally语句块中再次抛出异常。

  9. 不要使用异常控制程序的流程
    不应该使用异常控制应用的执行流程,例如,本应该使用if语句进行条件判断的情况下,你却使用异常处理,这是非常不好的习惯,会严重影响应用的性能。

  10. 不要捕获Throwable类
    在应用中不应捕获Throwable类,Error是Throwable类的子类,当应用抛出Errors的时候,一般都是不可恢复的情况。

  11. 为异常记录合适的文档
    为应用中定义的异常定义合适的文档,如果你写了一个自定义的异常却没有文档,其他开发者会不清楚这个异常的含义,为你定义的异常配备对应的文档是一个非常好的习惯。


目录
相关文章
|
5天前
|
Java
JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识
JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识。入坑JAVA因它的面向对象特性、平台无关性、强大的标准库和活跃的社区支持。
19 2
|
7天前
|
Java 开发者
Java中的异常处理:从基本概念到最佳实践
【4月更文挑战第30天】 在Java编程中,异常处理是确保程序健壮性和稳定性的关键机制。本文将深入探讨Java异常处理的基本概念,包括异常的分类、异常的抛出与捕获,以及如何有效地使用异常来增强代码的可读性和可维护性。此外,我们还将讨论一些关于异常处理的最佳实践,以帮助开发者避免常见的陷阱和误区。
|
7天前
|
XML Java 测试技术
Java异常处理神器:Guava Throwables类概念与实战
【4月更文挑战第29天】在Java开发中,异常处理是保证程序稳定性和可靠性的关键。Google的Guava库提供了一个强大的工具类Throwables,用于简化和增强异常处理。本篇博客将探讨Throwables类的核心功能及其在实战中的应用。
20 2
|
7天前
|
敏捷开发 机器学习/深度学习 Java
Java中的异常处理机制深入理解与实践:持续集成在软件测试中的应用探索自动化测试在敏捷开发中的关键作用
【4月更文挑战第29天】在Java编程中,异常处理是一个重要的概念。它允许开发者在程序执行过程中遇到错误或异常情况时,能够捕获并处理这些异常,从而保证程序的稳定运行。本文将详细介绍Java中的异常处理机制,包括异常的分类、异常的处理方式以及自定义异常等内容。 【4月更文挑战第29天】 随着敏捷开发和DevOps文化的兴起,持续集成(CI)已成为现代软件开发周期中不可或缺的一环。本文将探讨持续集成在软件测试领域内的关键作用、实施策略以及面临的挑战。通过对自动化构建、测试用例管理、及时反馈等核心要素的详细分析,揭示持续集成如何提高软件质量和加速交付过程。 【4月更文挑战第29天】 在当今快速发
|
7天前
|
安全 Java 网络安全
深入理解Java异常处理网络安全与信息安全:保护数据的关键策略
【4月更文挑战第29天】本文将深入探讨Java中的异常处理机制,包括异常的概念、分类、捕获和处理等方面。通过详细的解析和实例演示,帮助读者更好地理解Java异常处理的原理和应用。 【4月更文挑战第29天】在数字化时代,数据成为最宝贵的资产之一。随着网络攻击的日益猖獗,了解并实施有效的网络安全和信息保护措施变得至关重要。本文将深入探讨网络安全漏洞的概念、加密技术的重要性以及提升个人和企业的安全意识的必要性。我们将分析当前的安全挑战,并提供一系列实用的防护策略,旨在帮助读者构建一个更加安全的数字环境。
|
8天前
|
Java 程序员
Java 异常处理
4月更文挑战第22天
|
12天前
|
Java 数据库连接
深入理解Java异常处理机制
【4月更文挑战第24天】本文将探讨Java中的异常处理机制,包括异常的概念、分类、捕获和抛出等方面。通过深入了解异常处理机制,可以帮助我们编写更加健壮的程序,提高代码的可读性和可维护性。
|
12天前
|
Java 编译器 程序员
【Java基础】细说异常处理
【Java基础】细说异常处理
8 0
|
13天前
|
Java 编译器 开发者
Java从入门到精通:2.1.2深入学习Java核心技术——掌握Java异常处理
Java从入门到精通:2.1.2深入学习Java核心技术——掌握Java异常处理
|
15天前
|
Java 程序员 编译器
Java中的异常处理:从基础到高级
【4月更文挑战第22天】在软件开发过程中,异常处理是一个重要的环节。良好的异常处理机制可以使程序更加健壮,提高用户体验。本文将详细介绍Java中的异常处理机制,包括异常的基本概念、分类、捕获和处理等方面,并通过实例代码演示如何进行有效的异常处理。