捕获异常只是懒惰的错误检查?

时间:2013-01-04 14:32:37

标签: java exception-handling try-catch

我确定我会抓住这个......但是我来自一个没有try / catch块的语言,我正在学习Java异常捕获,我很难看到它不仅仅是一个懒惰的验证版本。我见过几个例子:

String Box [] = {"Book", "Pen", "Pencil"};
while(i<4)
{
    try
    {
        System.out.println(Box[i]);     
    }
    catch(ArrayIndexOutOfBoundsException e)
    {
        System.out.println("Subscript Problem " + e);
        i++;
    }

int y = 0;
int x = 1;
// try block to "SEE" if an exception occurs
try
{
    int z = x/y;
    System.out.println("after division");
} 
catch (ArithmeticException ae) 
{
    System.out.println(" attempt to divide by 0");
}

这些显然是非常基本的例子......但IMO要么是可怕的捕获错误的例子,要么没有充分的理由去做。在示例一中,如果我们循环Box中的元素数量,我们不需要检查越界索引。在示例二中,如果我们检查0的除数,我们不需要检查ArithmeticException

是否有 良好的 示例或原因使用try / catch块优于旧时尚变量验证?或者它只是“Java”方式?

7 个答案:

答案 0 :(得分:6)

这是一个没有例外的语言的例子:

if (!rename(file1, tmpName))
  if (!rename(file2, file1))
     if (!rename(tmpName, file2))
        return 0;
return -1;

另请注意,没有详细说明究竟出了什么问题。

与Java比较:

try {
   rename(file1, tmpName);
   rename(file2, file1);
   rename(tmpFile, file2);
   return true;
}
catch (IOException e) {
   e.printStackTrace();
   return false;
}

如果rename正确地将源名称和目标名称存储在异常消息中,我们就会确切地知道它在哪里变坏。

总而言之,异常机制的优点包括:

  • 允许您声明一个代码块,该代码块必须作为一个整体成功并且任何错误都得到相同的处理;
  • 允许您将所有错误处理委派给应用程序中的单个点,即所谓的异常障碍;
  • 异常对象存储重要的调试信息。

例外是巨大胜利,所有现代语言都有它们。

答案 1 :(得分:2)

你选择了最糟糕的例子,因为它们是未经检查的例外。如果您看到很多类型的try / catch块,我倾向于同意您的懒惰/不适当因素。但是,对于CHECKED异常,try / catch非常有用。难道你不厌倦C做

int status = thisStatementMayFail();
if (status > 0) {
    // do_stuff
}
else {
    // handleException();
}

我更喜欢Java的

try {
    thisStatementMayFail();
    // do stuff
} catch (Exception e) {
    // handleException
}

可能很懒,但绝对是更好的IMO。

答案 2 :(得分:1)

我认为异常是一种错误检查,但不以任何方式懒惰。

您在那里的示例可以是 lazy ,但是如果您将其更改为进行远程呼叫并且远程呼叫可能由于多种原因而失败(网络故障,远程服务故障)等),然后检查return code以查看是否存在错误(就像在C中完成的那样,带有整数返回码)会带来额外的复杂性。

异常背后的想法是,它们代表了在引发异常时无法恢复的错误。

关于捕获ArithmeticException,我认为对于大多数情况来说这将是错误的编程而不是懒惰的错误检测(但不是所有情况......虽然我想不到一个)。

答案 3 :(得分:1)

例外的一个主要论点是它们在正常流程之外进行。

使用您的示例:

public String getMyData(int index) {
  String box [] = {"Book", "Pen", "Pencil"};
  return box[index];
}

如果index是4,你会怎么做?调用方法的代码如何知道没有有效值(并且不要说“使用null”,因为许多方法可能会将null作为合法值返回)。

这是例外的主要用途。此外,异常层次结构用于通过知道如何处理它的方法来简化对情境的处理(在此示例中,如果抛出异常,调用方法可能会对使用null值感到满意。 ,或者可能觉得它必须停止该程序。)

答案 4 :(得分:1)

Java中的try / catch是一种机制,可以处理无法预料的(即不常见的)错误和异常,并将编程上下文传播到能够捕获和处理该条件的编码逻辑。

您提供的示例确实是try / catch的不良示例,并且基本上是惰性验证。糟糕的编码实践通常会使用try / catch而不是使用if测试来捕获异常。

try / catch有一个开销,比if-test更昂贵的操作,比如你将用于第二个例子:

if (y != 0) {
  int z = x/y
  // use z value
} else {
  System.out.println(" attempt to divide by 0");
}

I / O为异常处理提供了一个更好的示例。在大多数情况下,您可以打开文件,读取其内容并关闭文件,但有时文件被锁定,不存在,无法关闭等。而不是测试I / O可能出错的可能情况,您可以使用try-catch可以干净地处理 IOException FileNotFoundException

BufferedReader br = null;
try {
    File file = new File("target.dat");
    br = new BufferedReader(new FileReader(file));  
    String s;
    while ((s = br.readLine()) != null) {
          System.out.println(s);
    }
} catch (IOException ioe) {
    System.err.println("Error: " + ioe);     
} finally {
 if (br != null)
  try {
    br.close();
  } catch(IOException ioe) {
    System.err.println("Error: " + ioe);     
  }
}

答案 5 :(得分:0)

异常仅应用于特殊情况 - 在正常执行期间不应发生的事情。他们应该被抓住你实际上可以做些什么。

在非特殊情况下,例如验证外部输入,应首选if。这是因为如果它们被抛出,异常明显慢于if,但如果它们不被抛出则实际上更快。

答案 6 :(得分:0)

在尝试工作之前,并非所有错误都可以被验证。例如,您是否可以检测到网站将返回页面,直到您真正尝试?

没有例外,你必须有复杂的返回类型来向调用者报告错误。如果你想要纠正错误,这些返回类型会变得更复杂和复杂。

异常是一种很好的方法来解决错误并解除堆栈。但这必须在某个地方停止,并且某处需要catch