-1

我确定我会为此感到震惊......但我来自一个没有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,我们不需要检查 0 ArithmeticException

有没有一个很好的例子或理由说明使用try/catch块比老式的变量验证更好?还是只是“Java”方式?

4

7 回答 7

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将源名称和目标名称正确存储在异常消息中,我们将确切知道它哪里出错了。

综上所述,异常机制的优势包括以下几点:

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

例外是一个巨大的胜利,所有现代语言都有例外。

于 2013-01-04T14:49:45.223 回答
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。

于 2013-01-04T14:39:10.103 回答
1

我认为异常是一种错误检查,但绝不是懒惰的。

您那里的示例可能是惰性的,但是如果您将其更改为进行远程调用的东西并且远程调用可能由于多种原因(网络故障、远程服务故障等)而失败,然后检查return code以查看是否存在是一个错误(就像在 C 中所做的那样,带有整数返回码)引入了额外的复杂性。

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

关于 catch ArithmeticException,我认为在大多数情况下这将是糟糕的编程而不是懒惰的错误检测(但不是全部......虽然我想不出一个)。

于 2013-01-04T14:39:28.493 回答
1

异常的主要论据之一是它们在正常流程之外传播。

使用您的示例:

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

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

这是异常的主要用途。此外,异常的层次结构有助于通过知道如何处理它的方法来简化对情况的处理(在这个例子中,调用方法可能很乐意null在抛出异常的情况下使用该值,或者可能觉得它必须停止程序)。

于 2013-01-04T14:39:45.977 回答
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干净地处理IOExceptionFileNotFoundException 。

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);     
  }
}
于 2013-01-04T14:41:27.990 回答
0

异常应该只用于特殊情况——在正常执行期间根本不应该发生的事情。他们应该只被抓住,你实际上可以对他们做点什么。

在非异常情况下,例如验证外部输入,if应该首选 an。这是因为异常比抛出异常要慢得多if,但如果不抛出异常实际上会更快。

于 2013-01-04T14:39:26.797 回答
0

在尝试工作之前,并非所有错误都可以得到验证。例如,您能否检测到一个网站会在您实际尝试之前返回一个页面?

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

异常是纠正错误和展开堆栈的好方法。但这必须在某个地方停下来,而某个地方就是您需要catch.

于 2013-01-04T14:43:08.277 回答