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

时间:2008-12-10 14:32:32

标签: java exception return-value

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

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

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

还有其他建议吗?

修改错过了此选项

  • 为成功返回null - 这是不安全的吗?

修改解决方案:

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

17 个答案:

答案 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。这种类型是两种其他类型的联合联合(它包含每种类型的一个值)。

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

  1. 您可以拥有一个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();
    }
    
  2. 或者,您可以使用两种类型的不相交联合,作为Either<L, R>类。它包含一个值LR的值。此类为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");
    }
    
  3. 所有这些课程P2OptionEither在各种情况下都很有用。

答案 3 :(得分:3)

更多选择:

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

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

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我想我在问题中读到)。

几乎相同的问题已发布herehere

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

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

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

  

作为编程风格的问题,这个想法不是   在面向对象的编程语言中具有吸引力。   返回对象以表示计算结果    用于返回多个值的习惯用法。一些   建议你不必申报课程   对于不相关的值,但两者都不相关   值从单个方法返回。

我在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%;)

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

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