4

Java 中是否有可能摆脱捕获非RuntimeException异常的必要性?也许编译器标志?

我知道提升捕捉的原因,但想做简单而直接的工具来执行他们的要求。因此,如果出现问题,我不想赶上而是退出应用程序,并因有意义的异常而崩溃。通常这会像这样结束:

try {
     connection.close();
} catch (IOException e) {
    throw new RuntimeException(e);
}   

它引入了 4 行代码混乱,并RuntimeException在错误输出中引入了包装混乱。有时它甚至会激发人们将大块包裹try ... catch (Throwable ..)在任何东西上,这可能是我们心爱的“发生未知错误”警报框的原因......

4

6 回答 6

3

您可以将throws关键字与方法原型一起使用以避免try-catch阻塞。如果在代码中没有指定 catch 块来处理引发的异常,它最终会将异常抛出到 JVM 的默认异常处理程序,该处理程序会停止应用程序。

于 2011-04-25T13:26:50.300 回答
3

在第一次看到异常时使应用程序崩溃是非常糟糕的做法。特别是当某些工作未保存并且应用程序正在使用一些需要在应用程序终止执行之前释放和清理的资源时。一些非常流行的软件曾经这样做......而不是“修复”问题,他们在应用程序重新启动时引入了数据恢复功能。然而,诀窍,这不是好的软件工程。

至少,您的应用程序不应该在遇到第一个异常/错误时崩溃,而是通过有意义的消息恢复。将所有内容都包装在一个RuntimeException(甚至是Throwable)中是很懒惰的,尤其是对它不做任何事情。

Java 不支持任何类型的标志,因为有 1) 一种解决方法,以及 2) 处理这种情况的更好方法。例如 :

1.处理调用方法中的异常

您可以throws在方法声明中添加关键字,直到您的static public void main方法,如果不处理异常,最终将使用堆栈跟踪使应用程序崩溃。

class Foo {
   public void someMethod(....) throws IllegalArgumentException, IOException {
      ...
   }

   static public void main(String...args) throws Throwable {
      new Foo().someMethod();
   } 
}

此方法不提供任何可恢复性方法,并且可能会让您的用户不满意(如果他们从控制台运行应用程序,则会出现大量无意义的 stachtrace,或者如果他们从快捷方式或 GUI 启动应用程序,则根本什么都没有)。另外,如果你有一些获取的资源,当异常发生时你将无法清理它们。至少,在抛出上面的异常之前,你main应该输出一些东西。catch (Throwable e)就像是 :

class Foo {
   public void someMethod(....) throws IllegalArgumentException, IOException {
      ...
   }

   static public void main(String...args) {
      try {
         new Foo().someMethod();
      } catch (...) {
         // output or log exception here and, optionally, cleanup and exit
      }
   } 
}

**编辑**

考虑这种情况:一个程序正在初始化一些资源来处理一些数据,然后在处理过程中发生一些运行时异常(或错误),应用程序崩溃,但资源没有释放或释放。然而,在 Java 中,可以做到这一点

public E doSomething() throws RuntimeException {
   // declare a bunch of resources

   try {
      // process resources with unchecked exceptions
   } finally {
      // free resources
   }

   // return some result
}

并在错误或成功时干净地退出该方法,甚至可能为“后代”记录运行时错误。

2.记录错误并返回一些有意义的值

记录是一种非常好的做法。您可以向您的用户显示一些消息,告诉他们在不使整个事情崩溃的情况下无法执行该操作,并为您提供一些用户在做什么和在哪里做的痕迹。一个简单的日志系统可以是:

class Foo {
   static private final Logger LOG = Logger.getLogger(Foo.class.getName());

   public boolean doSomethingImpl(...) {
      boolean result = true;
      try {
        ...
      } catch (SomeException e) {
         LOG.log(Level.SEVERE, "meaningful message why method could not do something!", e);
         result = false;
      }
      return result;
   }

   public void doSomething() {
      if (!doSomethingImpl(...)) {
          // handle failure here
      }
   }
}

默认情况下,Logger会将所有内容输出到err输出流,但您可以添加自己的处理程序:

// loggers are singletons, so you can retrieve any logger at anytime from
// anywhere, as long as you know the logger's name
Logger logger = Logger.getLogger(Foo.class.getName());

logger.setUseParentHandlers(false);  // disable output to err
logger.addHandler(new MyHandler());  // MyHandler extends java.util.logging.Handler

Java 已经附带了一些默认的日志处理程序,其中一个写入文件

等等

于 2011-04-25T13:42:21.147 回答
1

我认为 JVM 没有办法解决这个问题。最好的办法是让你的方法重新抛出异常,从而消除代码中的“混乱”,然后让主程序抛出异常。这应该将错误传播到程序的顶部。

但是请记住,异常实际发生的地方是让用户知道发生了什么的更好的地方(即,当这个特定的 IOException 发生时它正在做什么)。如果所有错误都简单地传播到顶层,您将失去此解决方案。

于 2011-04-25T13:29:36.773 回答
1

您确实有能力将您的异常提升一个级别。这是一个例子

public class Foo {
    public Foo() {
        super();
    }
    public void disconnect(connection) throws IOException {
        connection.close();
    }
}
于 2011-04-25T13:31:20.453 回答
1

使用“Throws”来避免错误..但这不是好的编程实践

于 2011-04-25T13:36:55.360 回答
1

Java中是否有可能摆脱捕获非RuntimeException异常的必要性?

对于已检查的异常,您可以在捕获异常和在方法标头中将其声明为已抛出之间进行选择。

也许编译器标志?

不,没有编译器标志可以放松这一点。它是语言设计的基本部分。通过编译器开关放宽检查异常规则会导致严重的库互操作性问题。

于 2011-04-25T15:22:12.587 回答