有效使用 try-catch 块以及我们应该在哪里找到它们?

Posted

技术标签:

【中文标题】有效使用 try-catch 块以及我们应该在哪里找到它们?【英文标题】:Effective use of try-catch blocks & Where should we locate them? 【发布时间】:2013-11-09 21:30:38 【问题描述】:

我有一个接口类,一个实现类,一个异常类和一个主类。我不确定我是否在我的代码中有效地使用了 try catch 块。我在网上搜索并找到了类似的主题和问题,但我找不到我的问题的答案。我在主文件和实现文件中都使用了 try catch。有意义吗? 能请教一下效果吗?下面关于 try-catch 的逻辑对吗?

Interface Class:

public void createDatabase() throws DatabaseAlreadyCreated;


Implementation Class:

public void createDatabase() throws DatabaseAlreadyCreated

try

   // Create Database 
       //if database is already exist 
      throw new DatabaseAlreadyCreated();
         
catch (SQLException e) e.printStackTrace(); 
catch (ClassNotFoundException e) e.printStackTrace();



 Exception Class:

 public class DatabaseAlreadyExist extends Exception
 

    public DatabaseAlreadyExist(String str)
    
       System.out.println("database exist exception");
    
 



 Main Class:

 public static void main(String args[])
 
       try 
       
       x = ops.createDatabase();
        
       catch (DatabaseAlreadyExist e) 
       
         e.printStackTrace();
   
  

【问题讨论】:

【参考方案1】:

代码有些损坏....除非您有非常具体的原因,否则您永远不应直接扩展 Throwable 类,而应改为扩展 Exception(或类似 RuntimeException 的 Exception 的后代)。

使用这样的代码,除非您使用 catch (DatabaseAlreadyExistsException e) 显式捕获异常,否则您不太可能捕获异常

除此之外,您还有一些不推荐的错误处理问题...执行“printStackTrace”不是处理问题的有效方法,但我不确定您这样做是否只是为了表明你有处理它,或者没有(即你的真实代码只是做一个 printStackTrace 吗?).....


编辑:评论后更新...

好的,我比以前更了解您现在的要求。使用其他答案和 cmets 中描述的机制,我建议您执行以下操作:

public boolean checkDatabaseExists(...) 
    try 
        ... do the things you need to check the database exists.
        return true;
     catch (Exception e) 
        return false;
    

然后,在你的 main 方法中,你可以:

if (!checkDatabaseExists(...)) 
    createDatabase(...);
    

【讨论】:

我添加了 throwable 类并理解您的意思。此外,是的,我明确搜索数据库是否已经存在。我用***.com/questions/12414596/…中的问题代码做到了【参考方案2】:

一般而言,try/catch 块比使用 if/else 块更昂贵。

所以只使用 try/catch 可能会发生实际错误,例如在与服务器或数据库通信时,使用 try/catch 块是合适的。

如果要测试一个变量是否为“null”,那么使用 try/ctach 会很昂贵。 在这些情况下,您应该使用 if/else 之类的逻辑。

【讨论】:

我已经在数据库中苦苦挣扎,所以可以使用 try catch 而不是 if else ;)【参考方案3】:

在任何编程论坛中发起宗教战争的简单方法是:“处理错误的最佳方法是什么?” :) 但这是一个完全有效的问题。

在 Java 中,您可能已经知道,有两种异常:运行时可检测和编译时可检测。 (另一组标签是“未检查”,用于运行时,“已检查”,用于编译时。)编译时可检测异常已抛出专门为它们定义的异常,就像您对自定义数据库异常所做的那样。已检查和未检查的异常(例如:空指针或索引超出范围异常)之间的最大区别在于,已检查的异常是需要在抛出时进行处理,或者使用“抛出”委派超出方法的范围" 关键字,强制调用方法处理它。可以处理未选中的(通过 try/catch 块),但这不是必需的。未经检查的异常也只抛出特定的异常,它们是 RuntimeException 类的后代,它本身是 Exception 的后代。 (请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html 了解完整的低调)。虽然您可以使用 try/catch 块来捕获运行时异常,但您不能将这些类型的异常转变为由其特定运行时异常以外的任何东西处理(例如,运行时的空指针引用只能由 NullPointerException 对象处理或其超类对象之一,仅此而已)。

那么为什么要上“例外复习课”呢?因为一个异常是否应该被“向上”抛出给调用方法,或者在它发生的方法中就地处理,在很大程度上与异常生成代码之后的代码是否可以“生存”而没有成功完成 try/catch 块中的任何内容。后续代码本质上是否会留下可能的未检查(运行时)异常,例如空指针异常?很多时候,情况就是这样。或者,后续代码可能是可执行的,但处于不可靠状态(例如:未按需要设置的字段值等)。或者,在调用数据库进行更新时出现诸如 try/catch 块之类的情况,数据库数据状态可能与您想要完成的操作不正确。您需要根据上下文和目标(和依赖项)决定是否:

    向上抛出异常而不在本地处理或报告它,实质上将负担交给调用方法来处理它。 在本地处理异常并记录/报告(可能),然后在 catch () 块中使用“return”退出方法。 在本地处理异常并记录/报告(可能),然后继续执行方法中的代码。

正如我所说,你做什么取决于你需要做什么。就个人而言,我认为异常处理是每个给定方法的问题,需要在本地处理。抛出异常实际上意味着该方法未能完成其预期任务——除非调用方法能够弥补其失败,或者在异常创建方法内,后续代码仍然可以完成预期目标。将它扔给调用方法只是意味着您取消了这两个选项之一,更糟糕的是,它在发生时立即被抛出,因此您取消了在异常之后拾取的任何选项在使用“return”退出该方法或继续该方法之前。现在有时可能需要使用 try/catch 来测试代码中的条件;即,使用某些方法的异常抛出特性来确定您的代码接下来会做什么。然而,这通常是不受欢迎的,尤其是。如果有“更清洁”的方式可用。 [没有像 Java 纯粹主义者这样的纯粹主义者。 :)]

当然,有时向上抛出异常是可以的。但是在 IMO 中,调用方法不需要太关心受调用方法逻辑影响的任何对象或数据的状态。我认为它是一种更简单的方式来处理出现的不太重要的异常。在我自己的情况下,我更喜欢在使用可能为空的对象之前检查空对象引用。由于方法中的异常而为可返回对象分配 null 值并在 catch () 块中返回它是一种非常常见的技术,用于让调用方法知道被调用方法未能完成它的意图.例如:

public meth1() 
   Object o = meth2();
    if (o != null) 
       ... do what you need to ...
        else
       
       ... deal w/ no valid o object ...
       
     ...
   

private Object meth2()   
   Object retnme = new Object();
   ...
   try 
      ... give it yer best ...
    catch ( Exception e )
   
      logException(e); // a call to some logging method.
       ... clean up bad karma ...
       return null;
    
  ...
  return retnme;

所有这一切,关于您的代码的直接问题:基于上述内容并记住我不完全了解您的情况,我不明白您为什么应该将您创建的自定义异常抛出给调用方法,除非您出于某种原因特别想使用该异常向您要创建的数据库已经存在的调用方法发出信号。但是,如果知道这对调用方法没有特定用途 - 则无需这样做。这个决定的一部分取决于您是否希望使用任何实现您的接口的类来需要知道数据库是否存在。然而,避免使用这种策略的一种方法是编辑您的接口和类文件,以便该方法返回布尔值而不是 void。如果它返回“true”,则数据库已创建。如果“假”,则不是出于某种原因。您还可以让它返回一个 int 并根据它的值指示数据库创建是否成功。例如,值 0 可能表示成功,而值 1..n 可能表示失败原因,一个值当然表示 db 已经存在。

真的,天空才是极限。 :) 希望这对您有所帮助。

【讨论】:

【参考方案4】:

一般来说,只有当您无法处理当前级别的错误时,您才会抛出异常,并且您只会捕获您可以在该级别处理的错误。

【讨论】:

除非发生 SQLException 或 ClassNotFoundException ,否则我会查找数据库是否存在,如果存在则抛出异常。是否有更好的方法来查找数据库是否存在。我使用了链接中的代码***.com/questions/12414596/…

以上是关于有效使用 try-catch 块以及我们应该在哪里找到它们?的主要内容,如果未能解决你的问题,请参考以下文章

try-catch的使用以及细节

我应该在哪里以及如何在passportjs中检查访问令牌的有效性

C#中如何处理异常?怎么使用try-catch语句?

Try-Catch无法正确定位异常位置,我推荐2个有效技巧

Java异常处理只有Try-Catch吗?

Swift 4 中不确定代码块的 Try-catch 功能