Java 通过组件抛出异常,良好实践?
当一个子方法抛出异常时,封装在一个专用的“包”异常中会被认为是好的实践吗Java 通过组件抛出异常,良好实践?,java,java-8,Java,Java 8,当一个子方法抛出异常时,封装在一个专用的“包”异常中会被认为是好的实践吗 public String doStuff() throws UtilsException { try { throw new NullPointerException("test"); } catch (NullPointerException e) { throw new UtilsException("something occu
public String doStuff() throws UtilsException {
try {
throw new NullPointerException("test");
} catch (NullPointerException e) {
throw new UtilsException("something occured", e);
}
}
//use this exception for all classes of this package / component
public class UtilsException extends Exception {
private static final long serialVersionUID = 1L;
public UtilsException() {
super();
}
public UtilsException(String message, Throwable cause) {
super(message, cause);
}
public UtilsException(String message) {
super(message);
}
public UtilsException(Throwable cause) {
super(cause);
}
}
Optional.empty()
是否可以作为避免抛出/捕获复杂应用程序的替代方案
public Optional<String> doStuff() throws UtilsException {
try {
return Optional.of("ok");
} catch (NullPointerException e) {
LOG.error("Something append... {}", e.getMessage());
return Optional.empty();
}
}
public Optional doStuff()抛出UtilsException{
试一试{
返回可选。of(“ok”);
}捕获(NullPointerException e){
error(“Something append…{}”,e.getMessage());
返回可选的.empty();
}
}
首先,您应该永远不要捕获NullPointerException(或通常的运行时异常)并返回您正在执行的其他操作。
好的,也许有一些情况需要这样做(比如有缺陷的第三方api)
当您的程序有bug时,就会发生类似于这些异常(NullPointer、ClassCast、IllegalArgument等),您应该让它们发生
它们冒出气泡并在程序的某个高阶组件中处理它们
话虽如此,(还有一句臭名昭著的话)这取决于
异常“负责”通知错误,因此它们需要提供信息,以便调用方使用它们来决定要做什么。考虑以下事项:
public void readFile(String path) throws IOException {
// read file content
return content;
}
try {
return readFile("foo.txt");
} catch(FileNotFound e) {
// For this specific scenario not finding the file is not a problem
return "";
} catch(IOException e) {
// This we are not expecting to happen, if the file exists we should be
// able to read it, otherwise we should inform the user.
log.error(e);
display("We had a problem reading the file, Check the file permissions and try again");
}
正如您在上面的示例中所看到的,在这种情况下,您不希望将IOException包装到另一个异常中
因为您将删除客户端在发生错误时决定执行什么操作的能力
另外,请注意,IOException是“包装”的一种形式,因为异常也是对象,您可以使用继承
概括方法抛出的错误类型,然后抛出更具体的错误,以便调用方能够
决定做什么
何时包装。
在某些情况下,包装异常是一种很好的做法,也是一种可行的方法。
例如,如果您正在创建一个lib,其主要功能是获取天气信息
对于第一个版本,您保持了简单,并使用第三方api获取当天的值。
api的主要方法如下所示
public Weather getWeather(Date day) throws HTTPException {
return weather.get(day);
}
你的api做得很好,但是你注意到你对天气api和
你必须很快开始付钱。然后决定将结果缓存在数据库表中
因此,您可以减少请求的数量
public Weather getWeather(Date day) throws HTTPException, SQLException {
Weather w = getFromCache(day);
if (w != null) {
return w;
} else {
return getAndCache(day);
}
}
现在您遇到了一个问题,您不能将这个新异常添加到throws语句中,因为您肯定会中断
api的用户代码
如果您仔细想想,如果您从wheter api或api获取数据时遇到问题,那么您的api的用户不会感兴趣
从您的缓存中,他们只希望收到错误通知。这是一个很好的案例来包装这些异常
一个更通用的方法,如WeatherFetchException
正如你所看到的,这真的取决于
对我来说,经验法则是,让你的异常保持有意义,如果你想包装它们,只在
这是有意义的,当它没有消除调用方处理错误的能力时
仅仅为了它而包装异常绝对不是一种好的做法。在某些设置中,将低级异常包装为高级异常可能是一种好的做法,但如果您谈论的是
NullPointerException
,则不是。您甚至不应该捕获NullPointerException
。它在应用程序的所有级别中都具有相同的含义。可选
封装了一个可能不存在的值,而不是发生NullPointerException
的报告。首先要避免出现NullPointerException
。您可以使用可选的。NullPointerException只是为了解释我的设置。按照异常的来源进行包装似乎很有趣。然后您选择了一个非常糟糕的示例。考虑一下,<代码> CaleNoGuffDestExpOuts<代码>封装了在加载类字节时发生的<代码> IOExtExo/<代码>。一个特殊的情况是API层不允许检查异常,例如,将一个“代码>集合/<代码>视图考虑到数据库中。在那里,必须将基础存储系统的故障包装起来,例如,在IllegalStateException
s或NoSuchElementException
s中。我认为,这些都是更好的例子。当一个deep方法抛出某些东西时,抛出异常抛出调用堆栈以停止第一个调用方的执行是否也是一种糟糕的做法?看到了吗?