有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Exception和SQLException之间的java差异

有人能解释一下捕捉Exception和捕捉SQLException之间的区别吗?我知道,如果您选择打印异常错误,SQLException将打印出更多信息,但是还有其他的吗

try {
   //code
} catch(Exception ex) {
   //code
}

try {
   //code
} catch(SQLException ex) {
   //code
}

在catch块中使用ExceptionSQLException有什么好处和区别


共 (6) 个答案

  1. # 1 楼答案

    SQLException继承自Exception,因此SQLException将包含比Exception更多(更具体)的信息(通常适用于所有异常)

    您还可以有多个catch子句;因此,您可以首先尝试捕捉SQLException,但是如果它不是SQLException,那么您可以只捕捉一般的Exception

    一般来说,除非您打算以某种方式处理catch异常,否则不应该处理这些异常。您可以拥有一个顶级异常处理程序,该处理程序可以捕获任何出现在调用堆栈顶部的异常,这样您的程序就不会因未处理的异常而崩溃

  2. # 2 楼答案

    这不是唯一的区别

    捕获Exception是危险的,因为它还捕获所有的^{}(因此是未检查的异常),其中包括NullPointerException等明确的程序员错误<不要那样做

    另外,Exception是一个类似于其他类的类,因此您可以将其子类化并添加自己的构造函数/方法。例如,SQLException有一个^{} method,而Exception没有。如果只捕获Exception,则无法访问此方法

    一般来说,首先捕获“更精确”的异常是最好的。例如,使用新的(在Java7中…)文件API,您可以轻松区分文件系统级错误和其他I/O错误,因为FileSystemException扩展了IOException

    try {
        something();
    } catch (FileSystemException e) {
        // fs level error
    } catch (IOException e) {
        // I/O error
    }
    
  3. # 3 楼答案

    Exception是一个标准类,每个异常都从中继承

    SQLException是一个从Exception继承的类,专门为数据库(SQL)异常设计

    通过做

    try {
        // Your code here
    } catch (Exception e) {
        // Catching here
    }
    

    您正在捕获所有可能的异常类型。。。但是,您可能无法知道如何对特定异常做出反应

    但是通过这样做

    try {
        // Your code here
    } catch (SQLException e) {
        // Catching here
    }
    

    您知道异常是在处理数据库时发生的,这有助于您了解如何应对异常

  4. # 4 楼答案

    正如您所看到的SQLException扩展了异常。这就是唯一的区别。当您捕获异常时,您将捕获所有异常(这是不好的)。但是,当您捕获SQLException时,您只捕获它(这很好,因为这正是您所寻求的)

  5. # 5 楼答案

    A-解释

    SQLExceptionjava.lang.Exception的一个子类型,并且它正在实现Iterable<Throwable>类。程序员更喜欢抛出Exception类的不同子类型,因为在更高的级别上,他们希望捕获确切的子异常类,这样他们就可以确保在某个确切的场景中抛出特定的异常。因此,他们可以知道异常的确切来源

    B-示例

    认为您编写了一个抛出多个异常的方法。比方说,获取一个json字符串并对其进行解析,然后将其持久化到数据库中。考虑下面的方法;

    public boolean persistCustomer(String jsonString) throws SQLException, IOException {
        Connection conn = getConnection(); 
        PreparedStatement preparedStatement = null;
    
    
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            Customer customer = objectMapper.readValue(jsonString, Customer.class);
    
            preparedStatement = conn.prepareStatement(PERSIST_CUSTOMER);
    
            preparedStatement.setString     (1,  customer.getName());
            preparedStatement.setInt        (2,  customer.getAge());
            preparedStatement.setBoolean    (3,  customer.getIsRegular());
    
            preparedStatement.executeUpdate();
    
            return true;
        } catch (IOException e) {
            throw e;
        } finally {
            try {
                if (preparedStatement != null)
                    preparedStatement.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    

    在这个方法中,我们将JSON转换成一个Customer类,并且将Customer类持久化到数据库中

    以下几行抛出SQLException

        preparedStatement = conn.prepareStatement(PERSIST_CUSTOMER);
    
        preparedStatement.setString     (1,  customer.getName());
        preparedStatement.setInt        (2,  customer.getAge());
        preparedStatement.setBoolean    (3,  customer.getIsRegular());
    
        preparedStatement.executeUpdate();
    

    prepareStatement()、setter和executeUpdate()方法,它们都会抛出SQLException。但是,我们将字符串中的JSON转换为客户对象的行也会抛出除SQLException之外的几个异常

    Customer customer = objectMapper.readValue(jsonString, Customer.class);
    

    readValue()方法抛出JsonParseExceptionJsonMappingException以及IOException。所有这些异常都可以使用IOException捕获,因为与JSON相关的异常扩展了IOException

    我将提供两个不同的示例,以便很明显地理解为什么我们需要不同类型的异常

    C-错误做法:使用异常捕获所有异常

    public class BadPracticeExample {
    
        public static void main(String[] args) {
            MySQLUtil dbUtil =  new MySQLUtil();
    
            String jsonString = "{\"name\":\"Levent\",\"age\":31,\"isRegular\":true}";
    
            try {
                dbUtil.persistCustomer(jsonString);
            } catch (Exception e) {
                System.out.println("A problem occured");
            }
        }
    
    }
    

    如您所见,它捕获了异常,但是如果我们需要针对两个不同的问题源进行特殊的异常处理,我们该怎么办?persistCustomer可以抛出IOException或SQLException,如果我们需要执行不同的任务集来处理这些问题呢?当发生SQLException时,我想向数据库管理员发送一封电子邮件,当发生JSON解析问题时,我想在捕获IOException的情况下继续

    在这种情况下,您不能这样做。这是上面代码片段的输出,我们只确定发生了异常,但我们不知道它的来源

    A problem occured
    

    D-良好实践示例一:捕获的SQL异常

    public class GoodPracticeExample {
    
        public static void main(String[] args) {
            MySQLUtil dbUtil =  new MySQLUtil();
    
            String jsonString = "{\"name\":\"Levent\",\"age\":31,\"isRegular\":true}";
    
            try {
                dbUtil.persistCustomer(jsonString);
            } catch (SQLException e) {
                System.out.println("SQL Exception catched, SQL State : " + e.getSQLState());
                System.out.println("Error Code                       : " + e.getErrorCode());
                System.out.println("Error Message                    : " + e.getMessage());
            } catch (IOException e) {
                System.out.println("Cannot parse JSON : " + jsonString);
                System.out.println("Error Message     : " + e.getMessage());
            }
        }
    
    }
    

    如您所见,我们发现了JSON和SQL问题,在本例中,submethod试图在没有表的地方持久化DB。输出如下:

    SQL Exception catched, SQL State : 42000
    Error Code                       : 1142
    Error Message                    : INSERT command denied to user 'levent'@'example.com' for table 'CUSTOMER'
    

    所以我们已经捕获了SQL异常,并且我们拥有发送警报电子邮件所需的所有参数。我们可以在SQLException捕获块上添加额外的处理程序或实用程序方法

    D-良好实践示例II:在解析错误

    public class GoodPracticeExample {
    
        public static void main(String[] args) {
            MySQLUtil dbUtil =  new MySQLUtil();
    
            String jsonString = "{\"Zname\":\"Levent\",\"age\":31,\"isRegular\":true}";
    
            try {
                dbUtil.persistCustomer(jsonString);
            } catch (SQLException e) {
                System.out.println("SQL Exception catched, SQL State : " + e.getSQLState());
                System.out.println("Error Code                       : " + e.getErrorCode());
                System.out.println("Error Message                    : " + e.getMessage());
            } catch (IOException e) {
                System.out.println("Cannot parse JSON : " + jsonString);
                System.out.println("Error Message     : " + e.getMessage());
            }
        }
    
    }
    

    如果您注意到了,我破坏了JSON,导致IOException。现在在JSON字符串中,不是“name”,而是“Zname”,这将导致Jackson解析器失败。让我们检查一下这段代码的输出

    Cannot parse JSON : {"Zname":"Levent","age":31,"isRegular":true}
    Error Message     : Unrecognized field "Zname" (class com.divilioglu.db.utils$Customer), not marked as ignorable (3 known properties: "isRegular", "name", "age"])
     at [Source: (String)"{"Zname":"Levent","age":31,"isRegular":true}"; line: 1, column: 11] (through reference chain: com.divilioglu.db.utils.MySQLUtil$Customer["Zname"])
    

    正如您所看到的,我们捕获了特定场景,并且我们确信,这来自dbUtil中的行。persistCustomer()方法,如下所示

    Customer customer = objectMapper.readValue(jsonString, Customer.class);
    

    E-结论

    因此,通过扩展现有异常类来创建新异常是最佳实践。在一开始编写代码时,您可能会认为这是一种过激行为,您不需要额外的异常类,但当您需要区分问题的来源并独立处理它们时,您将需要它们

    在上面演示的这个示例中,我可以独立地捕获IOExceptionSQLException,这两个异常的源都来自同一个方法。我想区分两者,以便能够独立处理它们。如果只使用基类Exception包装所有异常,您就无法获得这种灵活性

  6. # 6 楼答案

    当您谈论捕获异常时,这都是关于层次结构的

    从技术上讲,Exception是捕获每个异常的超类。 如果您正在try块中编写与SQL相关的内容,并且您知道它甚至可能引发SQL异常。 那么你也可以这样申报

            try
            {
    
            }catch(SQLException ex)
            {
            Do this,when SQL Exception is caught.
            }
            catch(Exception ex)
            {
            Generic Exception - works for all
            }