从Java中的方法返回状态标志和消息的最佳方法

Dra*_*mon 27 java exception return-value

我有一个看似简单的场景,我想要一个简单的解决方案,但是哪个是"最正确"或"大多数Java"并不明显.

假设我在某个类中有一个小的身份验证(客户端客户端)方法.验证可能由于多种原因而失败,我想为控制流返回一个简单的布尔值,但也为用户返回一条String消息.这些是我能想到的可能性:

  • 返回一个布尔值,并传入一个StringBuilder来收集消息.这是最接近C风格的方式.
  • 抛出异常而不是返回false,并包含消息.我不喜欢这样,因为失败并非例外.
  • 使用boolean和String创建一个名为AuthenticationStatus的新类.对于一种小方法来说,这似乎有些过分.
  • 将消息存储在成员变量中.这会引入潜在的竞争条件,我不喜欢它意味着某些状态并不存在.

还有其他建议吗?

编辑关闭此选项

  • 返回null表示成功 - 这不安全吗?

编辑方案:

我选择了最OO解决方案并创建了一个小型AuthenticationResult类.我不会用任何其他语言来做这个,但我喜欢Java.我也喜欢返回String []的建议,因为它像null返回但更安全.Result类的一个优点是,如果需要,您可以获得包含更多详细信息的成功消息.

ada*_*dam 13

你可以使用例外....

try {
    AuthenticateMethod();
} catch (AuthenticateError ae) {         
    // Display ae.getMessage() to user..
    System.out.println(ae.getMessage());
    //ae.printStackTrace();    
}
Run Code Online (Sandbox Code Playgroud)

如果您的AuthenticateMethod发生错误,您发送一个新的AuthenticateError(扩展异常)

  • 我同意这一点.无法进行身份验证不是您希望调用者能够轻松忽略的错误. (2认同)
  • @Peter ...您正在寻找的格言是“永远不要使用异常来实现流程控制”。这不是流量控制。用户提供了希望登录的凭据,但凭据无法进行身份验证。为什么?也许不存在这样的用户名。也许密码已过期。谁知道? (2认同)

Ash*_*cer 11

返回一个带有boolean标志和String内部的小对象可能是最像OO的方式,尽管我同意这样的简单案例似乎有些过分.

另一种方法是始终返回一个String,并使null(或一个空字符串 - 您选择哪个)表示成功.只要在javadocs中清楚地解释了返回值,就不应该有任何混淆.

  • Null是一个坏主意,因为在某些时候你不会期待它. (7认同)
  • 返回空String或null表示失败被称为返回"sentinel值".两者都不是特别安全,因为你有效地击败了类型系统. (3认同)

Apo*_*isp 8

避免返回"哨兵值",尤其是null.最终会得到一个代码库,调用者无法在不阅读实现的情况下理解方法.在null的情况下,如果调用者忘记(或不知道)您的方法可能返回null,则可能最终得到NullPointerExceptions.

Bas Leijdekkers的元组建议是一个很好的,如果我想从一个方法返回多个值,我会一直使用它.我们使用的是P2<A, B>来自Functional Java库.这种类型是两种其他类型的联合联合(它包含每种类型的一个值).

抛出控制流的异常有点代码味道,但是检查异常是从方法中获取多种类型值的一种方法.其他更清洁的可能性存在.

  1. 你可以有一个Option<T>与两个子类抽象类Some<T>None<T>.这有点像null的类型安全替代方法,也是实现部分函数的好方法(没有为某些参数定义返回值的函数).该功能的Java库有一个全功能的Option类,它实现Iterable<T>,所以你可以做这样的事情:

    public Option<String> authenticate(String arg) {
       if (success(arg))
          return Option.some("Just an example");
       else
          return Option.none();
    }
    
    ...
    
    for(String s : authenticate(secret)) {
       privilegedMethod();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 或者,您可以使用两种类型的不相交联合作为Either<L, R>类.它包含一个值L或类型的值R.这个类实现Iterable<T>了两个LR,所以你可以做这样的事情:

    public Either<Fail, String> authenticate(String arg) {
       if (success(arg))
          return Either.right("Just an example");
       else
          return Either.left(Fail.authenticationFailure());
    }
    
    ...
    
    Either<Fail, String> auth = authenticate(secret);
    for(String s : auth.rightProjection()) {
       privilegedMethod();
    }
    for(Fail f : auth.leftProjection()) {
       System.out.println("FAIL");
    }
    
    Run Code Online (Sandbox Code Playgroud)

所有这些类,P2,Option,和Either在各种情况下非常有用.

  • Java8 有[可选](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html),它也提供了 (1.) 中描述的功能。 (2认同)