java中的异常或null

java中的异常或null,java,exception,null,wrapper,signature,Java,Exception,Null,Wrapper,Signature,我还有一个疑问。根据java的良好实践,如何管理找不到对象的情况,我们想知道原因 例如,如果有人在登录我们的系统时遇到问题,我们希望准确地告诉他们问题所在,我们不能返回null,因为我们失去了无法登录的原因。例如: public User login(String username, String password) { boolean usernameEmpty = (credentials.getUsername()==null || credentials.getUsername(

我还有一个疑问。根据java的良好实践,如何管理找不到对象的情况,我们想知道原因

例如,如果有人在登录我们的系统时遇到问题,我们希望准确地告诉他们问题所在,我们不能返回null,因为我们失去了无法登录的原因。例如:

public User login(String username, String password) {
    boolean usernameEmpty = (credentials.getUsername()==null || credentials.getUsername().isEmpty());
    boolean passwordEmpty = (credentials.getPassword()==null || credentials.getPassword().isEmpty());
    //getUserPassword return null if doesn't exist an user with username and password return null
    User user = getUserPassword(username,password);

    if (!usernameEmpty && !passwordEmpty && user!=null) {
        LOGGER.info("Found " + username);
    } else if (!usernameEmpty && !passwordEmpty && user==null) {
        LOGGER.info("There is no such username and password: " + username);
    } else if (usernameEmpty) {
        LOGGER.info("Username can not be empty ");
    } else if (passwordEmpty) {
        LOGGER.info("Password can not be empty ");
    }

    return user;
}
我可以想出两种方法来解决这个问题,各有利弊

第一个是使用异常,但我认为使用不同于预期的场景(如异常)不是一个好主意。出于这个原因,我放弃了它

第二个是让对象(用户)参与另一个对象来管理不同的可能性。例如,使用如下内容:

public class EntityObject<t> {
    //Is used to return the entity or entities if everything was fine
    private t entity;
    //Is used to inform of any checked exception
    private String exceptionMessage;

    //getters / setters / ..
}

public EntityObject<User> login(String username, String password) {
    boolean usernameEmpty = (credentials.getUsername()==null || credentials.getUsername().isEmpty());
    boolean passwordEmpty = (credentials.getPassword()==null || credentials.getPassword().isEmpty());
    User user = getUserPassword(username,password);
    EntityObject<User> entity = null;

    if (!usernameEmpty && !passwordEmpty && user!=null) {
        LOGGER.info("Found " + username);
        entity = new EntityObject<User>(user);
    } else if (!usernameEmpty && !passwordEmpty && user==null) {
        entity = new EntityObject<User>("There is no such username and password: " + username); 
    } else if (usernameEmpty) {
        entity = new EntityObject<User>("Username can not be empty ");
    } else if (passwordEmpty) {
        entity = new EntityObject<User>("Password can not be empty ");
    }

    return entity;
}
String loginResult = checkLoginError(...);
if (loginResult.equals(SUCCESS)) {
    User loggedInUser = login(...)
} else {
    // do stuff with the error message stored in loginResult
}
公共类EntityObject{
//用于在一切正常时返回一个或多个实体
私营t实体;
//用于通知任何选中的异常
私有字符串例外消息;
//getter/setters/。。
}
公共EntityObject登录(字符串用户名、字符串密码){
布尔usernamempty=(credentials.getUsername()==null | | credentials.getUsername().isEmpty());
boolean passwordEmpty=(credentials.getPassword()==null | | credentials.getPassword().isEmpty());
User User=getUserPassword(用户名、密码);
EntityObject实体=null;
如果(!usernamempty&&!passwordEmpty&&user!=null){
LOGGER.info(“找到的”+用户名);
实体=新的实体对象(用户);
}如果(!usernamempty&&!passwordEmpty&&user==null),则为else{
实体=新的EntityObject(“没有这样的用户名和密码:“+用户名”);
}else if(usernamempty){
实体=新的EntityObject(“用户名不能为空”);
}else if(passwordEmpty){
实体=新实体对象(“密码不能为空”);
}
返回实体;
}
与第一个选项相比,我更喜欢第二个选项,但我不喜欢必须更改方法签名以返回与通常(用户)不同的类(EntityObject)

通常是什么?它通常是如何管理的?
非常感谢

当系统中发生异常情况时,应使用异常。对于正常的流程和预期会发生的事情,应该避免使用异常

遵循良好的实体原则,您的方法应该只做一件事。因此,如果这是一种通过用户名和密码查找用户的方法,我认为最好是返回
null
。原因并没有消失。事实上,这是非常清楚的-没有这样的用户发现与提供的用户名和密码(这一原因包括与空用户名的问题,这是该方法的错误提供空用户名的登录方法的用户)。向方法中添加复杂的逻辑和其他实体将使代码更难维护和理解。无论如何,此方法的任务不是处理验证


如果网站或其某种API使用该类,则它们可以处理验证(如果用户名或密码为空)

对我来说,第二种选择看起来更好。也许,为了知道错误是什么,而不是用java代码编写消息,您可以使用可能的场景创建
enum
,并在前端代码中解决它,如果您确实需要消息,您可以在enum中创建构造函数来存储它。它将简化支持并在将来使用对象。此外,添加更多场景不会对您造成太大伤害

基本版本:

public class EntityObject<t> {
    //Is used to return the entity or entities if everything was fine
    private t entity;
    //Is used to inform of any checked exception
    private enum auth {
        NO_PASSWORD, NO_USERNAME, USER_DOES_NOT_EXIST, SUCCESS    
    }
}

我想说第二种方法很好。如果我是你,我会那样做

如果确实不想更改返回值,可以添加另一种方法来检查用户是否可以登录:

public static final String SUCCESS = "Success"
public String checkLoginError(String username, String password) {
    // do all the checks and return the error message
    // return SUCCESS if no error
}
现在,
login
方法可以是一行:

return getUserPassword(username,password);
您可以这样使用它:

public class EntityObject<t> {
    //Is used to return the entity or entities if everything was fine
    private t entity;
    //Is used to inform of any checked exception
    private String exceptionMessage;

    //getters / setters / ..
}

public EntityObject<User> login(String username, String password) {
    boolean usernameEmpty = (credentials.getUsername()==null || credentials.getUsername().isEmpty());
    boolean passwordEmpty = (credentials.getPassword()==null || credentials.getPassword().isEmpty());
    User user = getUserPassword(username,password);
    EntityObject<User> entity = null;

    if (!usernameEmpty && !passwordEmpty && user!=null) {
        LOGGER.info("Found " + username);
        entity = new EntityObject<User>(user);
    } else if (!usernameEmpty && !passwordEmpty && user==null) {
        entity = new EntityObject<User>("There is no such username and password: " + username); 
    } else if (usernameEmpty) {
        entity = new EntityObject<User>("Username can not be empty ");
    } else if (passwordEmpty) {
        entity = new EntityObject<User>("Password can not be empty ");
    }

    return entity;
}
String loginResult = checkLoginError(...);
if (loginResult.equals(SUCCESS)) {
    User loggedInUser = login(...)
} else {
    // do stuff with the error message stored in loginResult
}

您的问题似乎源于一个负责多个关注点的方法

我认为
login
方法不应该检查这些值是否为空。可能有某种用户界面(图形或非图形)采用用户名和密码-这应该是对用户输入执行验证的层

login
方法应该只关注给定的凭据是否与系统中的用户匹配。只有两种结果-是或否。为此,您可以使用
可选
。它应该允许字符串为空,因为这无论如何都不会匹配用户(假设用户不可能存在这种状态)

下面是一些伪代码:

void loginButtonPressed()
{
    if (usernameTextBox.text().isEmpty())
    {
        errorPanel.add("Username cannot be blank");
    }
    else if (passwordTextBox.text().isEmpty())
    {
        errorPanel.add("Password cannot be blank");
    }
    else
    {
        login(usernameTextBox.text(), passwordTextBox.text());
        // assign above result to a local variable and do something...
    }
}

public Optional<User> login(String username, String password)
{
    Optional<User> user = Optional.ofNullable(getUserPassword(username, password));
    user.ifPresentOrElse(
        user -> LOGGER.info("Found " + username),
        () -> LOGGER.info("Not found")
    );
    return user;
}
void loginButtonPressed()
{
if(usernameTextBox.text().isEmpty())
{
errorPanel.add(“用户名不能为空”);
}
else if(passwordTextBox.text().isEmpty())
{
errorPanel.add(“密码不能为空”);
}
其他的
{
登录名(usernameTextBox.text(),passwordTextBox.text());
//将上述结果赋给一个局部变量,然后执行某些操作。。。
}
}
公共可选登录(字符串用户名、字符串密码)
{
Optional user=Optional.ofNullable(getUserPassword(username,password));
user.ifpresentorese(
用户->记录器.info(“找到的”+用户名),
()->LOGGER.info(“未找到”)
);
返回用户;
}

Java的
null
值是该语言最糟糕的方面之一,因为在一个方法接收到null值之前,您无法真正判断它是否在接收。如果您使用的是IDE(我希望如此),您可以检查它是否可以控制您是否正在传递一个不应该传递的
null
值(IntelliJ可以通过将
@NotNull
注释添加到方法的参数中来实现)

因为它可能很危险,所以最好避免传递
null
s,因为一旦代码变得有点复杂,它肯定会导致错误

而且,我认为这是合理的