通过抛出异常实现Java流控制
我有一个关于更好的流量控制方法的问题困扰了我一段时间 我经常遇到这样的情况,我必须根据通过抛出异常实现Java流控制,java,exception,control-flow,Java,Exception,Control Flow,我有一个关于更好的流量控制方法的问题困扰了我一段时间 我经常遇到这样的情况,我必须根据null或notnull 所以我有两个选择,我知道如何应对: 检查是否为空: public class BasedOnNullFlowControl { public String process(String login) { String redirectUri = getRedirectUri(login); if (redirectUri != null) {
null
或notnull
所以我有两个选择,我知道如何应对:
检查是否为空:
public class BasedOnNullFlowControl {
public String process(String login) {
String redirectUri = getRedirectUri(login);
if (redirectUri != null) {
return redirectUri;
} else {
return "Your login is taken";
}
}
private String getRedirectUri(String login) {
Optional<Login> loginFromDb = checkLoginExists(login);
if (loginFromDb.isPresent()) {
return null;
} else {
return "some-redirect-url";
}
}
private Optional<Login> checkLoginExists(String login) {
return Optional.empty(); //assume this value comes from some API
}
private class Login {}
}
公共类BasedUnlullFlowControl{
公共字符串进程(字符串登录){
String redirectUri=getRedirectUri(登录名);
if(重定向URI!=null){
返回重定向URI;
}否则{
返回“您已登录”;
}
}
私有字符串getRedirectUri(字符串登录){
可选loginFromDb=checkLoginExists(登录);
if(loginFromDb.isPresent()){
返回null;
}否则{
返回“一些重定向url”;
}
}
私有可选CheckLoginList(字符串登录){
return Optional.empty();//假设此值来自某个API
}
私有类登录{}
}
或异常情况下中断流程:
public class ExceptionFlowControl {
public String process(String login) {
return getRedirectUri(login);
}
private String getRedirectUri(String login) {
Optional<Login> loginFromDb = checkLoginExists(login);
loginFromDb.ifPresent(l -> {
throw new LoginExistsException();
});
return "some-redirect-url";
}
private Optional<Login> checkLoginExists(String login) {
return Optional.empty();
}
private class LoginExistsException extends RuntimeException {
}
private class Login {}
}
公共类例外流控制{
公共字符串进程(字符串登录){
返回getRedirectUri(登录);
}
私有字符串getRedirectUri(字符串登录){
可选loginFromDb=checkLoginExists(登录);
loginFromDb.ifPresent(l->{
抛出新的LoginExistException();
});
返回“一些重定向url”;
}
私有可选CheckLoginList(字符串登录){
返回可选的.empty();
}
私有类LoginExistException扩展了RuntimeException{
}
私有类登录{}
}
我知道,异常应该只在异常情况下使用,但我的情况并不例外,而且第二种解决方案看起来更适合我,因为我可以添加一些异常处理程序(如Spring中的)并最终将其转换为一些漂亮的Http状态代码。控制器方法过程
没有被几十个空检查所污染
你们这些聪明人能告诉我应该使用哪一种解决方案吗?或者可能还有第三个呢?这取决于:
- 如果在逻辑中缺少值(或null)是一种正常的和预期的情况,那么您不应该抛出异常,而应该相应地提供它。考虑使用null对象模式-而不是返回null返回某个对象,它将表示一个“非值”对象,那么您可以省略检查空值,因为您的逻辑应该相应地处理这样的空对象(通常您不需要在逻辑中编写一行代码来服务这样的对象)。
- 如果情况是你真的无法继续,你应该抛出一个异常。应使用异常来表示应用程序中的错误。如果您可以事先避免异常(例如使用
)检查用户是否指定了正确的文件名),那么您应该这样做(除非它确实超出了正常的逻辑流程,并且您无法继续)file.exists()
在您的特定情况下,为什么不返回重定向uri,该uri指向带有“用户不存在”消息类型的某个页面?异常方法允许代码部分之间的依赖性较小,因此第一种方法非常差。使用它,您需要从
checkLoginExists()
到过程传递一个加载了特殊含义的null
值(null==login take
)
但是,引发异常不是getRedirectUri()
的工作,应该在checkLoginExists()
中完成。我怀疑getRedirectUri()
是否也要负责检查登录名是否存在。更不用说使用null
或Optional
只会给您一个成功/失败的二元概念。如果登录存在,但被锁定,那么您必须禁止登录,并创建同名的新用户。您可能希望重定向到其他页面以指示登录已锁定
不过,这是基于意见的,高度依赖于具体情况,没有明确的规则可以遵循
编辑(现在所有的喧闹都结束了):这是一个被广泛接受的观点,正常的流量控制不应该在例外情况下进行。然而,法线的定义并不那么容易定义。您不会像这样编写代码
int[] array = ...
int i = 0;
try {
while(true) {
array[i]++;
i++;
}
} catch(ArrayIndexOutOfBoundsException e) {
// Loop finished
}
然而,如果你没有使用像上面这样一个可笑的简单例子,它就会进入灰色区域
还要注意,异常与应用程序错误不同。试图通过验证所有内容来解决异常是不可能的(或者至少是不明智的)。如果我们考虑新用户试图登记用户名的情况,我们希望防止重复用户名。您可以检查副本并显示错误消息,但两个并发请求仍有可能试图注册相同的用户名。此时,其中一个将出现异常,因为数据库将不允许重复(如果您的系统在任何情况下都是合理的)
验证很重要,但异常并没有什么真正的例外。您需要优雅地处理它们,因此,如果最终不得不处理异常,为什么还要麻烦验证呢。如果我们以我在评论中写的某个例子为例,您需要防止重复和诅咒单词作为用户名,您可能会想到类似的方法(假设这是在getRedirectUri()
:
首先,如果使用optionals,可以完全避免null
检查:
public class BasedOnNullFlowControl {
public String process(String login) {
String redirectUri =
return getRedirectUri(login).orElse("Your login is taken");
}
private Optional<String> getRedirectUri(String login) {
return checkLoginExists(login).map(ifExists -> "some-redirect-url");
}
private Optional<Login> checkLoginExists(String login) {
return Optional.empty(); //assume this value comes from some API
}
private class Login {}
}
公共类BasedUnlullFlowControl{
公共字符串进程(字符串登录){
public class BasedOnNullFlowControl {
public String process(String login) {
String redirectUri =
return getRedirectUri(login).orElse("Your login is taken");
}
private Optional<String> getRedirectUri(String login) {
return checkLoginExists(login).map(ifExists -> "some-redirect-url");
}
private Optional<Login> checkLoginExists(String login) {
return Optional.empty(); //assume this value comes from some API
}
private class Login {}
}