从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是从方法中获取多种类型值的一种方法。 其他更清洁的可能性存在。
-
您可以使用
Option
抽象类,其中包含两个子类Some
和None
。 这有点像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(); } -
或者,您可以使用两种类型的不相交并集,作为
Either
类。 它包含一个值为L
或R
。 此类为L
和R
实现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"); }
所有这些类, P2
, Option
和Either
都适用于各种情况。
还有一些选择:
- 为每种类型的故障返回单独的枚举值。 枚举对象可以包含消息
- 返回一个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%;))
将消息解析委托给另一个类也可能是一种好习惯。 但这取决于您的应用需求(大多数情况下,它需要i18n吗?)
这似乎是其他编程语言中常见的习惯用法,但我无法弄清楚哪一个(我在问题中读到的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; }
- org.openqa.selenium.UnhandledAlertException:意外警报打开
- 为什么我的程序在文件存在时捕获/抛出FileNotFoundException?
- Java中是否有未处理的exception处理程序?
- 你能弄清楚为什么这个程序会触发IllegalStateException吗?
- Java Mail超时和connectiontimeout处理
- JVM如何知道在运行时捕获exception的位置?
- Gson.toString()给出错误“IllegalArgumentException:多个名为mPaint的JSON字段”
- 是否可以使用exception而不是详细的空检查?
- 无法复制:“比较方法违反了其总合同!”