简体   繁体   English

为什么Java在Exception / Throwable类中没有setMessage?

[英]Why doesn't Java have setMessage in Exception/Throwable classes?

I am not able to understand why Java doesn't allow to change exception message of an exception of type Exception (or its superclass Throwable) once it has been created. 我无法理解为什么Java一旦创建就不允许更改Exception类型异常(或其超类Throwable)的异常消息。 It allows to change the stackTrace using setStackTrace but not the message. 它允许使用setStackTrace更改stackTrace,但不允许更改消息。

The use case I have seems genuine to me and would appreciate some alternative. 我用过的用例对我来说似乎是真实的,并会欣赏一些替代方案。

Use case 用例

I have a controller service X that calls let's say 10 other dependent services. 我有一个控制器服务X,调用让我们说10个其他依赖服务。 To make debugging easy, if a dependent service throws some exception we want to surface some identifiers from service X to its upstream to identify the failed request easily. 为了简化调试,如果依赖服务抛出一些异常,我们希望从服务X向其上游显示一些标识符,以便轻松识别失败的请求。 For this we have requestId which we create and set for each dependency. 为此我们有requestId,我们为每个依赖项创建和设置。

Now to avoid duplication across all dependent services and simplify code, we can create a common interceptor that allows us to do some work before and after each call. 现在为了避免所有相关服务的重复并简化代码,我们可以创建一个通用拦截器,允许我们在每次调用之前和之后做一些工作。 Something like - 就像是 -

// do some work

requestId = getRequestId(); // create or somehow get requestId
dependentService.setRequestId(requestId);

try {
  dependentService.call();
}
catch (Exception e) {
  e.setMessage(e.getMessage() + ... + requestId);
  throw e;
}

//do some work

But Java doesn't allow us to set message. 但Java不允许我们设置消息。 At the same time, we want to preserve the exception and its type (which could be any of the custom types defined by dependent services), so I don't want to do something like throw new Exception(e.getMessage() + ...) 同时,我们希望保留异常及其类型(可以是依赖服务定义的任何自定义类型),因此我不想执行诸如throw new Exception(e.getMessage() + ...)

It's not really what it's meant for, but you could attach another exception with addSuppressed : 算不上什么它的意思为,但你可以附加其他异常,并addSuppressed

} catch (Exception e) {
  e.addSuppressed(new ExtraInfoException(...));
  throw e;
}

where ... contains the extra info you want to include. where ...包含您要包含的额外信息。

The advantage of this over adding to the exception message is that you can define your ExtraInfoException so that it has the info you want in fields, rather than having to parse it back out of the exception message. 相对于添加异常消息,这样做的好处是,您可以定义ExtraInfoException ,使其在字段中具有您想要的信息,而不必将其从异常消息中解析出来。

With that said, a more idiomatic way to attach more exception info it would be: 话虽如此,附加更多异常信息的更惯用的方法是:

} catch (Exception e) {
  throw new ExtraInfoException(e, ...);
}

which has exactly the same advantage of allowing you to return structured information, with the additional advantage that you can catch ExtraInfoException directly, rather than catching Exception and then hunting for the extra info reflectively. 它具有允许您返回结构化信息的完全相同的优点,另外的优点是您可以直接捕获ExtraInfoException ,而不是捕获Exception ,然后反复寻找额外的信息。

Why doesn't Java have setMessage in Exception/Throwable classes? 为什么Java在Exception / Throwable类中没有setMessage?

The answer to your question is that they (the library designers) did not think that changing a message on an exception was a useful thing to do. 您的问题的答案是他们(图书馆设计师)并不认为更改异常消息是一件有用的事情。

To a large degree 1 , the designers have taken the view that they shouldn't design the APIs to directly support all possible use-cases ... including the obscure ones that almost nobody will encounter. 在很大程度上1,设计师们所持的看法,他们不应该设计API直接支持所有可能的使用情况......包括晦涩那些几乎没有人会遇到。 Like your one 2 . 喜欢你的2

And in your case, there are other ways to achieve what you are trying to do; 在你的情况下,还有其他方法来实现你想要做的事情; see the other answers. 看到其他答案。

I did a quick search of the Java bugs database to see if someone else had put in an RFE to request a setMessage method for Throwable or Exception . 我快速搜索了Java错误数据库,看看是否有其他人放入了一个RFE来为ThrowableException请求一个setMessage方法。 I couldn't find anything. 我找不到任何东西。 If your requirement was even slightly common, there would probably be an RFE with an explanation of why it was declined. 如果你的要求甚至有点普遍,那么可能会有一个RFE,解释为什么它被拒绝了。


1 - Obviously, there are exceptions to this, but that is beside the point. 1 - 显然,这有例外,但这不是重点。

2 - Obviously you would disagree that your use-case is obscure, but that that is also beside the point. 2 - 显然你会不同意你的用例是模糊的,但这也是不重要的。 The question is why they haven't implemented this, not whether they were wrong. 问题是为什么他们没有实现这一点,而不是他们是否错了。 (Asking / debating whether they were wrong is off-topic, because it is a matter of opinion.) (询问/辩论他们是否错了是偏离主题的,因为这是一个意见问题。)

Resetting a message it's some kind of rewriting the history. 重置消息它是某种重写历史记录。 You have a catch block when you catch exception and handle them. 当你捕获异常并处理它们时,你有一个catch块。 If you need to throw an exception during the handling, it's a different problem and an exception should be different. 如果你需要在处理过程中抛出异常,那就是一个不同的问题,异常应该是不同的。

} catch (SomeException e) {
 // here we have SomeException and we want to handle it.
 // if we can't we throw a new one, because we have a problem with handling.
 // if the handling problem cause is SomeException we put it at the cause.
 throw new AnotherException("with some message", e);
}

And in the stacks trace we will see that we have AnotherException because of SomeException which gives us information about the root of problem. 在堆栈跟踪中,我们将看到由于SomeException我们有AnotherException ,它为我们提供了有关问题根源的信息。

Just simply throw new instance like this: 只需简单地抛出这样的新实例:

try {
...
} catch(Exception ex) {
   throw new Exception ("new message", ex);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM