我在Spring应用程序中使用了外部SOAP服务。 SOAP服务在连接时会引发异常,因此我在try catch块中捕获了该异常:
try {
response = soapService.callService(request);
} catch (Exception e){
throw SoapServiceException("explaining",e);
}
if (BAD_STATUS_CODE.equals(response.getStatusCode()) {
throw CustomException("explaining", e);
}
return response;
您会注意到,我也想在响应不是调用者期望的响应时引发异常,例如,可能是因为有效的请求格式,但在soap服务中找不到值。
这是一个好习惯吗?我试图防止将响应对象包装在另一个保留错误代码的对象中。我认为,如果服务调用者处理肥皂异常或响应异常之类的特殊情况,那会很好。谢谢你的建议。
答案 0 :(得分:2)
异常是Java编程语言的功能,但并非必须使用。好吧,您可能必须抓住现有的,而不必再筹集新的。
这是您的应用程序/框架/库的设计决策。通常,在整个代码库中一致地处理错误的方法会更好。没有更好的通用方法。这是一个集体选择,还取决于程序的一般预期行为。
简单的设计
“天真”或至少简单的实现通常会在许多不受支持的情况下引发异常,因为这是中断执行,获取错误日志和进行调查的简便方法。
以这种方式看待事物,检查异常并不一定值得。您的异常可以从RuntimeException派生,您无需声明它们,而只需在出现问题时引发它们即可。
这种设计的缺点是,在许多情况下,开发人员可能会引发异常,而大多数“异常”情况实际上是应用程序中的常见情况。找不到文件?好吧,这很常见。网络不可用?这是意料之中的。该服务没有返回您的期望?这种情况可能比您想像的更多。
至少在我们拥有数千台机器和十万台TPS之类的产品中,一切都会发生。
寻求更可靠的实施方式
因此,通常情况下,您会分离出您认为将要发生并必须处理的内容(例如网络请求超时或临时数据库不可用)或永不发生的内容(文件工件分配的一部分丢失)或提供给函数的参数无效(代码错误)。
对于真正的异常,您将保留异常,并且通常使它们成为RuntimeException / unchecked,因为无需执行任何操作。您只希望记录并重新报告这些错误。
对于其余所有内容,中间可能会有例外,但全局没有例外。您想处理它们并将其视为正常行为。
在这种情况下,选择取决于您的设计。
但是通常情况下,如果我必须采取行动并在发生这种情况时能够正常进行,那么我也希望没有例外。通常,对于网络请求,我会认为“超时”实际上是有效的响应,并作为我在业务领域中建模的值的一部分而返回。
要在我的数据域中包含“错误和错误”代码部分,我可以累积/汇总错误并微调对错误的反应方式。相反的例外是全有或全无。
这为我选择如何反应提供了更大的灵活性...就像我执行10个请求,一次超时,返回错误时,我不想出现异常。我希望结果和“合并”策略取决于应用程序的功能方面。
在您的BadStatus示例中,如果这是我得到的错误代码,则将其视为异常,因为我提供了无效的输入(代码中的错误)。但是,如果那是因为没有网络,或者是由于外部故障,那对我来说是预期的行为,所以我不会抛出。
那是我的设计选择,那是我一直在进行设计选择的团队。这不一定是通用选择。只要确保大家都同意如何处理这种情况并且它与您的总体软件设计相符
已检查的异常
他们强迫您去处理它,这可能是祝福还是诅咒,具体取决于上下文。
这是您设计中的选择。
您是否仅在异常情况下抛出异常,而该异常不应发生,并将其用作错误检测机制?然后我认为它们没有用,当我使用这种策略时,我将它们包装在派生的RuntimeException中以简化我的代码,在我的代码的几个关键区域中,我通用了所有可以视为框架lvl的机制,所以我确保总是返回正确的响应(即使该响应有错误),也可以集中记录。
但是,如果您再次认为客户端应始终对其进行处理,请使用已检查的异常。这样做的问题是,调用者通常无法直接做任何事情,他可能需要包装成许多中间对象才能转发它,或者拥有大量的检查异常列表。
所以我不喜欢他们。但这又是您和团队的设计决定。
答案 1 :(得分:0)
在行为异常时在代码中引发异常是完全可以的。只需确保标记您的方法
void testMethod() throws CustomException, CustomException2, ..
,以便方法的调用者知道有可能引发异常的可能性。 未捕获的异常将导致您的程序终止,因此请务必捕获并正确处理。
答案 2 :(得分:0)
[HttpDelete]
[Route("api/employee/delete")]
public void Delete(int Id)
{
using (EmployeeDBEntities db = new EmployeeDBEntities())
{
try
{
Employee emp = db.Employees.FirstOrDefault(e => e.EmpId == Id);
db.Employees.Remove(emp);
db.SaveChanges();
}
catch (Exception ex)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(ex.Message)
});
}
}
}
答案 3 :(得分:-1)
在我一直在工作的所有项目中,我们都像您一样使用了,我们抛出了异常,而不是将其包装在任何响应对象中。对我来说很好。