我有一个看似简单的场景,我想要一个简单的解决方案,但是哪个“最正确”或“大多数Java”并不明显。
假设我在某个类中有一个小的身份验证(客户端客户端)方法。验证可能由于多种原因而失败,我想为控制流返回一个简单的布尔值,但也为用户返回一条String消息。这些是我能想到的可能性:
还有其他建议吗?
修改错过了此选项
修改解决方案:
我选择了最OO解决方案并创建了一个小型AuthenticationResult类。我不会用任何其他语言来做这个,但我喜欢Java。我也很喜欢这个建议 返回String [],因为它像null返回但更安全。 Result类的一个优点是,如果需要,您可以获得成功消息以及更多详细信息。
答案 0 :(得分:13)
您可以使用例外....
try {
AuthenticateMethod();
} catch (AuthenticateError ae) {
// Display ae.getMessage() to user..
System.out.println(ae.getMessage());
//ae.printStackTrace();
}
然后如果您在AuthenticateMethod中发生错误,则发送一个新的AuthenticateError(扩展异常)
答案 1 :(得分:10)
返回一个同时包含boolean标志和String的小对象可能是最像OO的方式,尽管我同意这样的简单案例似乎有些过分。
另一个替代方法是始终返回一个String,并使null(或一个空字符串 - 您选择哪个)表示成功。只要在javadocs中清楚地解释了返回值,就不会有任何混淆。
答案 2 :(得分:8)
避免返回“sentinel值”,尤其是null。最终会得到一个代码库,调用者无法在不阅读实现的情况下理解方法。在null的情况下,如果调用者忘记(或不知道)您的方法可能返回null,则调用者最终可能会得到NullPointerExceptions。
Bas Leijdekkers的元组建议是一个很好的,如果我想从一个方法返回多个值,我会一直使用它。我们使用的是来自P2<A, B>
库的Functional Java。这种类型是两种其他类型的联合联合(它包含每种类型的一个值)。
抛出控件流的异常有点代码味道,但是检查异常是从方法中获取多种类型值的一种方法。其他更清洁的可能性存在。
您可以拥有一个Option<T>
抽象类,其中包含两个子类Some<T>
和None<T>
。这有点像null的类型安全替代方法,也是实现部分函数的好方法(没有为某些参数定义返回值的函数)。 Functional 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();
}
或者,您可以使用两种类型的不相交联合,作为Either<L, R>
类。它包含一个值L
或R
的值。此类为Iterable<T>
和L
实现R
,因此您可以执行以下操作:
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");
}
所有这些课程P2
,Option
和Either
在各种情况下都很有用。
答案 3 :(得分:3)
更多选择:
简单元组示例,实际实现可能需要更多:
class Tuple<L, R> {
public final L left;
public final R right;
public Tuple( L left, R right) {
this.left = left;
this.right = right;
}
}
答案 4 :(得分:1)
您可以返回错误消息的集合,空白表示没有问题。这是对你的第三个建议的改进。
答案 5 :(得分:1)
我个人认为使用boolean创建一个名为AuthenticationStatus的新类,而String是最像Java的方式。虽然它看起来有点矫枉过正(它很可能)但对我来说似乎更清洁,更容易理解。
答案 6 :(得分:1)
仅仅因为认证失败并不常见并不意味着它并不例外。
在我看来,身份验证失败是检查异常的 poster-child 用例。 (嗯......也许文件不存在是规范的用例,但身份验证失败是关闭#2。)
答案 7 :(得分:0)
这里有很多好的答案所以我会保持简短。
我认为用户进行身份验证失败可被视为已检查异常的有效案例。如果您的编程风格倾向于处理异常,那么就没有理由不这样做。它还删除了“如何从方法返回多个值,我的方法做了一件事它验证用户”
如果你要返回多个值,那么花10分钟创建一个通用的PairTuple(也可以是一对TripleTuple,我不会重复上面列出的例子)并以这种方式返回你的值。 我讨厌让小的dto风格的对象返回各种多样的值,它们只会让这个地方变得杂乱无章。
答案 8 :(得分:0)
成功的身份验证应该是“正常”的情况,因此身份验证失败是例外情况。
无论如何,用户有哪些不同的状态字符串。我只能看到两个,成功或失败。任何进一步的信息都是潜在的安全问题。 具有例外的解决方案的另一个优点是不能以错误的方式调用它,并且故障情况更加明显。没有例外,你写:
if (authenticate()) {
// normal behaviour...
}
else {
// error case...
}
您可以无意中调用忽略返回值的方法。然后在没有成功验证的情况下执行“正常行为”代码:
authenticate();
// normal behaviour...
如果您使用例外,则不会发生这种情况。如果您决定不使用异常,请至少命名该方法,以便明确它返回一个状态,例如: G:
if (isAuthenticated()) {
//...
}
答案 9 :(得分:0)
这似乎是其他编程语言中常见的习惯用语,但我无法弄清楚哪一个(C我想我在问题中读到)。
尝试从单个函数返回两个值可能会产生误导。但正如通过这样做的尝试所证明的那样,它也可能非常有用。
如果这是以前发布的应用程序中的常见流程,那么绝对创建带有结果的小类应该是正确的方法。
这是关于从函数返回两个值的引用:
作为编程风格的问题,这个想法不是 在面向对象的编程语言中具有吸引力。 返回对象以表示计算结果 用于返回多个值的习惯用法。一些 建议你不必申报课程 对于不相关的值,但两者都不相关 值从单个方法返回。
我在java的功能请求中发现它允许multiple return values
查看“评估”部分日期:2005-05-06 09:40:08
答案 10 :(得分:0)
我很可能会选择以下内容:
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
}
使用这种“设计”,只有在身份验证失败时才能请求消息(我希望这种情况发生的时间是99,99%;)
将消息解析委托给另一个类也可能是一种好习惯。但这取决于您的应用需求(大多数情况下,它需要i18n吗?)
答案 11 :(得分:0)
这是您有这种要求的唯一方法吗?如果没有,只需生成一个带有isSuccessful标志和消息字符串的通用Response类,并在任何地方使用它。
或者你可以让方法返回null来显示成功(不漂亮,并且不允许返回成功和消息)。
答案 12 :(得分:0)
我自己使用“小班”,通常是内班。我不喜欢使用参数来收集消息。
此外,如果可能失败的方法是“低级别” - 比如来自应用服务器或数据库层,我宁愿返回一个带有返回状态的枚举,然后将其转换为一个字符串。 GUI级别。如果您要将代码国际化,请不要在低级别传递用户字符串,因为您的应用服务器一次只能用一种语言进行响应,而不是让不同的客户端使用不同的语言。
答案 13 :(得分:-1)
我会先选择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;
}
}
这并不奇怪,它在框架中的许多地方都已完成。
答案 14 :(得分:-1)
返回对象。如果需要,它允许您将其他功能添加到类中。 Java中的短期对象可以快速创建和收集。
答案 15 :(得分:-1)
如何返回一个字符串。空或无效成功。发生故障时出现错误消息。 最简单的方法。但不确定它是否读得好。
答案 16 :(得分:-2)
我通常只返回一个存储所有返回信息的数组,而不是为返回类型创建一个特殊对象。好处是您可以使用新元素扩展此数组,而无需创建新类型和混乱。在从特定方法返回数组以正确解析数组时,您必须准确知道哪些元素应该存在的缺点。通常我同意某些结构,比如第一个元素总是布尔指示成功,第二个是带描述的字符串,其余是可选的。 例如:
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;
}