我应该在if-else块中抛出异常吗



以下是代码:

public Response getABC(Request request) throws Exception {
Response res = new Response();
try {
if (request.someProperty == 1) {
// business logic
} else {
throw new Exception("xxxx");
}
} catch (Exception e) {
res.setMessage(e.getMessage); // I think this is weird
}
return res;
}

这个程序运行良好。我认为它应该重新设计,但怎么设计呢?

在try块中抛出异常并立即捕获它是没有意义的,除非catch块抛出不同的异常。

你的代码这样会更有意义:

public Response getABC(Request request) {
Response res = new Response();
if (request.someProperty == 1) {
// business logic
} else {
res.setMessage("xxxx");
}
return res;
}

如果您的业务逻辑(在条件为true时执行)可能引发异常,则只需要try-catch块。

如果您没有捕捉到异常(这意味着调用者将不得不处理它),您可以不使用else子句:

public Response getABC(Request request) throws Exception {
if (request.someProperty != 1) {
throw new Exception("xxxx");
}
Response res = new Response();
// business logic
return res;
}

如果您从方法中抛出异常,那么为什么要捕获它呢?要么你返回一个带有"xxxx"消息的响应,要么抛出一个异常,让这个方法的调用者来处理它

public Response getABC(Request requst) {
Response res = new Response();
if(request.someProperty == 1){
//business logic
else{
res.setMessage("xxxx");
}
}
return res;
}

public Response getABC(Request requst) throw Excetpions {
Response res = new Response();
if(request.someProperty == 1){
//business logic
else{
throw new Exception("xxxx");
}
return res;
}

public void someMethod(Request request) {
try {
Response r = getABC(request);
} catch (Exception e) {
//LOG exception or return response with error message
Response response = new Response();
response.setMessage("xxxx");
retunr response;
}
}

故意抛出异常然后直接捕获它似乎是不对的,可以这样重新设计
可以用res.setMessage("xxxx");改变throw new Exception("xxxx");
然后可以保留捕获异常部分,以便捕获业务逻辑内部可能发生的异常。

public Response getABC(Request requst) {
Response res = new Response();
try{
if(request.someProperty == 1){
//business logic
else{
res.setMessage("xxxx");
}
}catch(Exception e){
res.setMessage(e.getMessage);
}
return res;
}

首先,重构工作方法时要更加小心,尤其是在执行手动重构时。也就是说,引入一个变量来保持message可能是改变设计的一种方式:

public Response getABC(Request requst) throw Excetpions {
String message = "";
try{
if(request.someProperty == 1){
//business logic
else{
message = "xxxx";
}
}catch(Exception e){
message = e.getMessage();
}
Response res = new Response();
res.setMessage(message);
return res;
}

假设business logic在成功时自行返回。

我认为您可能错过了try/catch的要点。代码使用异常系统将任何异常消息气泡发送给调用者。这可能在嵌套调用堆栈的深处,而不仅仅是您正在查看的那个"抛出">

换句话说,示例代码中的"throws"声明利用了这种机制向客户端传递消息,但它几乎肯定不是try/catch的主要目标用户。(同样,这是一种草率、有点便宜的传递信息的方式——它可能会导致混乱)

无论如何,这个返回值不是一个好主意,因为异常通常没有消息,可以重新包装。。。不过总比什么都没有好。异常消息并不是最好的工具,但像这样在高层处理异常仍然是个好主意。

我的观点是,如果重构此代码,请确保查找可能在代码库中的任何地方(至少在消息处理期间调用的任何地方)抛出的运行时异常——即使这样,您也应该将catch/return消息保留为catch-all,以防出现您意想不到的运行时例外。您不必将错误"Message"作为响应消息返回——它可能是一些俏皮的"我们此时无法处理您的请求",但一定要将堆栈跟踪转储到日志中。您当前正在将其扔掉。

当您已经抛出检查异常时,为什么要使用try/catch语句?

已检查异常通常用于某些语言,如C++或Java,但不用于Kotlin等新语言。我个人限制使用它。

例如,我有一个这样的类:

class ApiService{
Response getSomething() throw Exception(); 
} 

这感觉干净可读,但破坏了异常处理机制的实用性。实际上,getSomething()通常不会抛出已检查的异常,但仍然需要像它那样行事?当ApiService的上游有人知道如何处理像这样的不可预测的无法预防的选中的异常就足够了。

public Response getSomething(Request req) throws Exception{
if (req.someProperty == 1) {
Response res = new Response();
// logic 
} else {
thows Exception("Some messages go here")
}
}

我鼓励这样做:

public Response getSomething(Request req){
if (req.someProperty == 1) {
Response res = new Response();
// logic 
return res;
} else {
return ErrorResponse("error message"); // or throw RuntimeException here if you want to
}
}

为了获得更多见解,我之前提到的Kotlin不支持检查异常,原因有很多。

以下是由StringBuilder类实现的JDK的示例接口:

Appendable append(CharSequence csq) throws IOException;

这个签名写的是什么?它说,每次我将字符串附加到某个东西(StringBuilder、某种日志、控制台等)时,我都必须捕获这些IOExceptions。为什么?因为它可能正在执行IO(Writer也实现了Appendable)……所以它会在所有地方生成这样的代码:

try {
log.append(message)
}
catch (IOException e) {
// Must be safe
}

这是不好的,请参阅有效Java,第三版,第77项:不要忽略异常。

看看这些链接:

  • 已检查和未检查异常
  • Java的检查异常是一个错误(Rod Waldhoff)
  • 检查异常的问题(Anders Hejlsberg)

异常机制有三个目的:

  1. 立即禁用正常程序流并返回调用堆栈,直到找到合适的catch块
  2. 以异常类型、消息和可选的附加字段的形式提供上下文,catch块代码可以使用这些字段来确定操作过程
  3. 供程序员查看以进行取证分析的堆栈跟踪。(这以前做起来很贵)

对于一个机制来说,这是一个很大的功能。为了让程序尽可能简单——对于未来的维护人员来说——因此,只有在真的必须使用的情况下,我们才应该使用这种机制。

在您的示例代码中,我希望任何throw语句都是非常严重的,表明出现了问题,并且代码应该在某个地方处理此紧急情况。在继续阅读程序的其余部分之前,我需要了解出了什么问题以及问题的严重程度。在这里,这只是一根弦的华丽回归,我会挠头,想知道"为什么这是必要的?"而额外的努力本可以花得更好。

所以这段代码并没有它所能做到的那么好,但只有当你有时间做一个完整的测试时,我才会更改它。更改程序流可能会引入细微的错误,如果需要修复任何内容,您需要将更改牢记在心。

同样,如果您想在失败时获得JVM返回的特定异常消息,那么您可以在catch块中使用带有方法getMessage()或printStackTrace()的try-catch。所以在这里你可以修改你的代码,比如:

public Response getABC(Request request) throws Exception {
Response res = new Response();
try {
if (request.someProperty == 1) {
// business logic
} 
} catch (Exception e) {
res.setMessage(e.getMessage); 
}
return res;
}

最新更新