java中的异常或null

时间:2018-04-19 07:29:25

标签: java exception null wrapper signature

我有下一个疑问。根据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;
}

我可以想出两个有利有弊的选择来解决它。

第一个一个在于使用异常,但我认为使用不同的方案(例外情况除外)并不是一个好主意。出于这个原因,我放弃了它。

第二个一个涉及另一个对象中的对象(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;
}

我比第一个选项更喜欢第二个选项,但我不喜欢我必须更改方法签名以返回与通常(用户)不同的类(EntityObject)。

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

5 个答案:

答案 0 :(得分:3)

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

遵循良好的SOLID原则,您的方法应该只做一件事。因此,如果它是一种通过用户名和密码查找用户的方法,我会说最好的方法是返回null。原因不会丢失。实际上非常清楚 - 没有找到这样的用户提供的用户名和密码(这个原因包括空用户名的问题,并且方法的用户为登录方法提供空用户名)。向方法添加复杂逻辑以及为此类事物添加其他实体将使您的代码更难以维护和理解。无论如何,这种方法的工作不是处理验证。

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

答案 1 :(得分:1)

对我来说,第二种选择看起来更好。也许,要知道错误是什么而不是在java代码中编写消息,你可以创建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    
    }
}

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("Password cannot be empty"),
        NO_USERNAME("Username cannot be empty"), 
        USER_OR_PASSWORD_DOES_NOT_EXIST("No such username or password exist"),
        SUCCESS("OK");
        public String message;
        public auth(String message) {
            this.message = message;
        }   
    }
}

答案 2 :(得分:1)

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

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

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);

你可以像这样使用它:

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

答案 3 :(得分:1)

看起来你的问题源于一种造成多重顾虑的方法。

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

login方法只应关注给定凭据是否与系统中的用户匹配。只有两个结果 - 是或否。为此,您可以使用Optional<User>。它应该容忍字符串为空,因为它永远不会与用户匹配(可能是用户不可能在这种状态下存在)。

这是一些伪代码:

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;
}

答案 4 :(得分:1)

Java的null值是该语言最糟糕的方面之一,因为您无法确定方法是否在接收到空值之前发生。如果您正在使用IDE(我希望如此),您可以检查它是否可以控制是否传递null值,而不应该有一个值(IntelliJ可以通过添加@NotNull注释来执行此操作方法的参数)。

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

另外,我认为只有在有可能存在的情况下才检查null是合理的。

如果您想表达某个值是否存在,最好使用Optional<T>。如果由于某种原因,可以传递null值而不是实际值,则可以创建一个实用程序方法,其唯一的关注点是验证参数是否正确:

public Optional<EntityObject<User>> login(String username, String password) {
    //isNotNull shouldn't be necessary unless you can't validate your parameters
    //before passing them to the method.
    //If you can, it's not necessary to return an Optional
    if (isNotNull(username, password)) {
        //Since I don't know if a password must always be present or not 
        //I'm assuming that getUserPassword returns an Optional
        return Optional.of(new EntityObject<User>(getUserPassword(username,password).orElse(AN_EMPTY_USER)));
    } else {
        return Optional.Empty();
    }
}

无论如何,我认为验证输入不应该是login方法的关注点,即使您不想使用Optional;它应该用另一种方法来完成。