27

我听说抓捕java.lang.Error被认为是不好的做法。我目前正在加载一个不保证在 PATH 上的 .dll,并且希望切换到用户配置的位置,以防它不在。

try {
    System.loadLibrary("HelloWorld");
} catch(UnsatisfiedLinkError ule){
    System.load("C:/libraries/HelloWorld.dll");
}

有没有更好的方法来做到这一点?还是在UnsatisfiedLinkError这里可以接受?

4

4 回答 4

39

除了就如何在技术上克服问题提供建议之外,我想花点时间解释一下为什么它首先被认为是“不好的做法”。

让我们从澄清Error类是什么开始。


在 java 中,会抛出错误和异常(它们是主要类型)。使用throw关键字完成上述操作之一。每个扩展基本的类java.lang.Throwable都可以被抛出。

有两个类继承自基本Throwable类:ExceptionError. 他们的文档中解释了这两者之间的区别:

ErrorThrowable的子类,表示合理的应用程序不应尝试捕获的严重问题。大多数此类错误是异常情况。[...]

来源

Exception及其子类是Throwable的一种形式, 它指示合理的应用程序可能想要 捕获的条件。

来源


如上所述,错误和异常是分开的,因为它们的来源不同。Error通常表示应用程序无法从中恢复的问题。因此,他们不应该被抓住。

对于 a 也是如此RuntimeException,但它用于指示高级层(例如方法)的问题。而Error表示低级问题(例如运行时)。


因此,既然您了解您只能捕获可以从中恢复的异常和错误,那么您的问题的答案应该很清楚了。

是的,捕获 是完全合理的UnsatisfiedLinkError,因为您的应用程序可以从中恢复。


我在我的博客上的一篇文章中介绍了上述内容(更详细并带有示例)和一些扩展信息。

于 2012-06-13T16:01:08.207 回答
2

您应该只在非常特定的情况下捕获错误。如果您已经探索了所有其他可能性,则只有捕获和错误。我完全同意 Lukas Knuth 所说的一切。但我还有一个小补充。如果您要捕获任何类型的错误,请确保从尽可能窄的范围内捕获错误。此外,如果可能,请确保您捕获错误的方法声明为最终方法。原因是捕获错误通常会导致一些非常不稳定的程序。考虑到您在稍后扩展为调用其他方法的方法上捕获了错误,所有这些底层方法现在也将被覆盖的捕获(无意中)捕获到错误。

如果您需要捕获错误,请以狭窄、受控的方式进行。

于 2014-09-18T09:36:19.747 回答
0

loadLibrary 调用 findLibrary() 这会很有帮助,但它受到保护,最好的办法是编写自己的扩展 ClassLoader 的类。类加载器有一个名为 findLibrary() 的受保护方法,它将返回库的路径,如果不存在则返回 null。这样你就可以只检查 null 而不是捕获错误。我不确定这是否真的“更好”,但它会消除您对 try catch 的需要;

于 2012-06-13T14:58:54.080 回答
0

如果您是防御性编码并且可以从问题中恢复,那么它不是 Java Error。如果这样的问题不太可能,那么创建一个子类Exception并抛出并捕获它。如果可能出现这样的问题,那么它甚至不应该抛出Exception; 但是,应该是常规代码流的一部分。

try {
  if (config.hasCustomDLL()) {
    System.load(config.getCustomDLL());
  } else {
    System.loadLibrary(Config.DEFAULT_DLL);
  }
} catch (UnstatisfiedLinkError e) {
  System.out.println("Error loading DLL: " + e);
}

Errors意味着非常糟糕的故障,而不是可恢复的“故障”,如果有合适的解决方法,它们甚至都不是故障。不要使设计用于处理故障的系统过载,这相当于以多种方式配置系统的能力。

于 2012-06-13T16:12:06.423 回答