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

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

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

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

还有其他建议吗?

编辑错过此选项

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

编辑方案:

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

返回一个同时包含boolean标志和String的小对象可能是最类似于OO的方式,尽管我同意这样的简单案例似乎有些过分。

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

你可以使用例外….

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

然后,如果您的AuthenticateMethod发生错误,您发送一个新的AuthenticateError(扩展exception)

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

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

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

  1. 您可以使用Option抽象类,其中包含两个子类SomeNone 。 这有点像null的类型安全替代方法,也是实现部分函数的好方法(没有为某些参数定义返回值的函数)。 Functional Java库有一个function齐全的Option类,它实现了Iterable ,所以你可以这样做:

     public Option authenticate(String arg) { if (success(arg)) return Option.some("Just an example"); else return Option.none(); } ... for(String s : authenticate(secret)) { privilegedMethod(); } 
  2. 或者,您可以使用两种类型的不相交并集,作为Either类。 它包含一个值为LR 。 此类为LR实现Iterable ,因此您可以执行以下操作:

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

所有这些类, P2OptionEither都适用于各种情况。

还有一些选择:

  • 为每种类型的故障返回单独的枚举值。 枚举对象可以包含消息
  • 返回一个int,并有一个单独的方法从数组中查找相应的消息
  • 创建一个可以包含两个值的通用实用程序元组类。 这样的课程可以在更多地方使用。

简单的元组示例,实际实现可能需要更多:

 class Tuple { public final L left; public final R right; public Tuple( L left, R right) { this.left = left; this.right = right; } } 

您可以返回错误消息集合,空白表示没有问题。 这是对您的第三个建议的改进。

我个人认为使用布尔值创建一个名为AuthenticationStatus的新类,而String是最像Java的方式。 虽然它看起来有点矫枉过正(它很可能)但它对我来说似乎更清洁,更容易理解。

仅仅因为认证失败是常见的并不意味着它并不例外。

在我看来,身份validation失败是检查exception的海报子使用案例。 (嗯……也许文件不存在是规范用例,但身份validation失败是关闭#2。)

我自己使用“小class”,通常是内class。 我不喜欢使用参数来收集消息。

此外,如果可能失败的方法是“低级别” – 例如来自应用服务器或数据库层,我宁愿返回具有返回状态的枚举,然后将其转换为GUI级别的字符串。 如果您要将代码国际化,请不要在低级别传递用户字符串,因为您的应用服务器一次只能使用一种语言进行响应,而不是让不同的客户端使用不同的语言。

这是你有这种要求的唯一方法吗? 如果没有,只需生成一个带有isSuccessful标志和消息字符串的通用Response类,并在任何地方使用它。

或者你可以让方法返回null来显示成功(不漂亮,并且不允许返回成功和消息)。

我很可能会去做类似的事情:

 class SomeClass { public int authenticate (Client client) { //returns 0 if success otherwise one value per possible failure } public String getAuthenticationResultMessage (int authenticateResult) {} //returns message associated to authenticateResult } 

使用这种“设计”,只有在身份validation失败时才能请求消息(我希望这种情况发生的时间为99,99%;))

将消息解析委托给另一个类也可能是一种好习惯。 但这取决于您的应用需求(大多数情况下,它需要i18​​n吗?)

这似乎是其他编程语言中常见的习惯用法,但我无法弄清楚哪一个(我在问题中读到的CI猜测)。

在这里和这里发布几乎相同的问题

尝试从单个函数返回两个值可能会产生误导。 但正如通过这样做的尝试所certificate的那样,它也可能非常有用。

如果这是以前发布的应用程序中的常见流程,那么绝对创建带有结果的小类应该是正确的方法。

这是关于从函数返回两个值的引用:

作为编程风格的问题,这种想法在面向对象的编程语言中并不吸引人。 返回对象来表示计算结果是返回多个值习惯用法。 有些人建议你不必为不相关的值声明类,但是不应该从单个方法返回不相关的值。

我在java的function请求中发现它允许多个返回值

看看“评价”栏目日期:2005-05-06 09:40:08

成功的身份validation应该是“正常”的情况,因此身份validation失败是例外情况。

无论如何,用户有哪些不同的状态字符串。 我只能看到两个,成功或失败。 任何进一步的信息都是潜在的安全问题。 具有例外的解决方案的另一个优点是不能以错误的方式调用它,并且故障情况更加明显。 没有例外,你写道:

 if (authenticate()) { // normal behaviour... } else { // error case... } 

您可以意外地调用忽略返回值的方法。 然后在没有成功validation的情况下执行“正常行为”代码:

 authenticate(); // normal behaviour... 

如果您使用例外,则不会发生这种情况。 如果您决定不使用exception,请至少为方法命名,以便明确它返回一个状态,例如:

 if (isAuthenticated()) { //... } 

这里有很多好的答案,所以我会保持简短。

我认为用户进行身份validation失败可以被视为已检查exception的有效情况。 如果您的编程风格倾向于处理exception,那么就没有理由不这样做。 它还删除了“如何从方法返回多个值,我的方法做了一件事它validation用户”

如果你要返回多个值,那么花10分钟创建一个通用的PairTuple(也可以是一对TripleTuple,我不会重复上面列出的例子)并以这种方式返回你的值。 我讨厌让小的dto风格的对象返回各种多样的值,它们只会让这个地方变得杂乱无章。

如何返回一个字符串。 空或无效成功。 发生故障时出现错误消息。 最简单的方法。 但不确定它是否读得好。

返回对象。 如果需要,它允许您将其他function添加到类中。 Java中的短期对象可以快速创建和收集。

我会首先选择Exception选项。

但是,排在第二位,我更喜欢C风格的技术:

 public boolean authenticate(Client client, final StringBuilder sb) { if (sb == null) throw new IllegalArgumentException(); if (isOK()) { sb.append("info message"); return true; } else { sb.append("error message"); return false; } } 

这并不奇怪,它在框架中的许多地方都已完成。

我通常只返回一个存储所有返回信息的数组,而不是为返回类型创建一个特殊对象。 好处是您可以使用新元素扩展此数组,而无需创建新类型和混乱。 在从特定方法返回数组以正确解析数组时,您必须确切知道哪些元素应该存在的缺点。 通常我同意某些结构,比如第一个元素总是布尔指示成功,第二个是带描述的字符串,其余是可选的。 例:

 public static void main(String[] args) { Object[] result = methodReturningStatus(); if(!(Boolean)result[0]) System.out.println("Method return: "+ result[1]); } static Object[] methodReturningStatus() { Object[] result = new Object[2]; result[0] = false; result[1] = "Error happened"; return result; }