我有以下Java方法:
public Class createClass(Class class) {
try {
// retrieve the professor of the class and check if he exists
Professor professorFound = professorRepository.findById(class.getProfessorId());
if (professorFound != null) {
// if the professor exists, then check if he already has a class
// with the same id
List<Class> classes = professorFound.getClasses();
List<Class> classFound = classes.stream().... // loop to find the class...
// if he has, throw an exception
if(!classFound.isEmpty()) {
throw new ClassAlreadyRegisteredException();
} else {
// if he does not have, then create the class
Class class = new Class();
professorFound.getClasses().add(class);
return professorRepository.save(professorFound);
}
} else {
// if the professor does not exist, throw an exception
throw new ProfessorNotFoundException();
} catch (Exception e) {
// if there is any other error during the communication with the database,
// throw a generic IOException
throw new ClassIOException();
}
}
基本上,我需要的是抛出特定的Exceptions(如果请求中通知的教授不存在,或者教授已经有一个具有相同id的类(,或者如果在与数据库的通信过程中出现任何其他错误,则抛出通用的IOException
。
然而,按照我开发的方式,如果抛出任何特定的Exception
,try块将捕获异常并抛出一个通用IOException。
我该如何解决这个问题?
我很想了解这种情况下的最佳实践是什么我应该分别捕获每个特定的异常并抛出两次吗这是个好做法吗
编辑:
这就是我的ClassAlreadyRegisteredException
的样子:
public class ClassAlreadyRegisteredException extends ApiException {
private static final long serialVersionUID = 1L;
public ClassAlreadyRegisteredException(String code, String message, String developerMessage, String origin, HttpStatus status) {
super(code,message,developerMessage,origin, status);
}
}
这就是我的ApiException
的样子:
@Data
@AllArgsConstructor
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class ApiException extends RuntimeException{
private static final long serialVersionUID = 1L;
private String code;
private String userMessage;
private String developerMessage;
private String origin;
private HttpStatus status;
}
提前谢谢。
接球并重新投球。
try {
... same as before ...
} catch (ClassAlreadyRegisteredException | ProfessorNotFoundException e) {
throw e;
} catch (Exception e) {
// if there is any other error during the communication with the database,
// throw a generic IOException
throw new ClassIOException();
}
或者,记住该异常以便稍后抛出。
Exception fail = null;
try {
….
// save exception in place of existing throws
// for example:
fail = new ClassAlreadyRegisteredException();
…
} catch (Exception ex) {
...same as original...
}
if (fail != null) {
throw fail;
}
我使用这两种技术;选择取决于在任何给定的情况下什么更简单。两者都没有无可争辩的好。
对于catch和re-show方法,您必须使捕获和重新抛出的异常列表与您在try子句中实际抛出的异常保持一致。在较大的情况下,我会通过使用异常层次结构来避免这个问题,这样我就可以捕获公共基类。
对于save和throw方法,您必须安排控制流,以便在检测到失败后不执行任何重要操作,因为您没有立即的"throw"命令来退出try子句。尽管如此,在某些情况下,它足够简单;最初的例子就是这样的。
选中与未选中异常
在catch块中抛出异常是完全可以接受的。一个常见的用例是获取一个已检查的Exception
并抛出一个未检查的RuntimeException
,这将允许异常冒泡到需要处理的位置。
您将希望对连接/IO、SQL异常等用例使用已检查的异常。。
处理已检查的异常
为了回答您的问题,在大多数连接到数据库的库中,如果存在任何连接问题,将抛出一个选中的IOException
。对于这些情况,您可以始终在方法签名public Class createClass() throws IOException
中指定
这指定CCD_ 9的任何调用方都必须履行处理CCD_。
或
您可以将其重新列为RuntimeException
try {
...
} catch (IOException e) {
throw new RuntimeException(e); // <- send the original exception so you can preserve the exception and stacktrace.
}
这基本上会上升到STDOUT或您的框架指定的任何处理程序。
注意:
然而,覆盖所有Exception
并抛出更具体的ClassIOException
可能会产生意想不到的后果。
如果您有一个NullPointerException
,它将被您的catch (Exception e)
块捕获,并重新生成为ClassIOException
这样做会破坏堆栈跟踪,并导致错误日志更难调试。
了解检查异常的构成
另一个技巧是考虑一下你的Exception
病例是什么。
若它们是应用程序、服务或业务逻辑的标准流,则这些可能不是合适的例外。
ClassAlreadyRegisteredException
和ProfessorNotFoundException
在您的应用程序中可能不是例外情况。。。除非你的教授已经指定了这些。
有时,如果情况需要,这些可以作为RuntimeException
抛出。
最佳实践
关于如何处理例外情况,仍有许多意见。因此,以下是我在处理异常时问自己的一些经验法则问题
- 堆栈跟踪是否保留?我能追溯到根异常吗
- 这是一个常见的逻辑,代表了一个偏离我的应用程序所提供的特殊情况吗
- 如果我抛出这个异常,那么调用这个方法来处理这个异常逻辑是绝对必要的吗