代码之家  ›  专栏  ›  技术社区  ›  hugoware

在try、catch、finally中抛出异常与返回错误

  •  3
  • hugoware  · 技术社区  · 17 年前

    我很确定我已经知道答案了,但我还是很好奇在尝试、捕获、最终阻塞中处理错误的意见-- 但当你重复你自己的时候。

    顺便说一句-我不是在说用户输入-而是用它作为例子,因为它是清晰和简短的

    想想这段代码…

    try {    
        if (success) {
            return someSuccessMessage;
        }
        else {
            logError("User input not correct format");
            return someErrorMessage; // repeats itself
        }
    }
    catch (Exception ex) {
        logError(ex.Message);
        return someErrorMessage; // repeats itself
    }
    

    假设我们有一个函数,如果它失败了,我们希望返回一条错误消息,因为异常是不相关的——我们的函数没有成功,用户不需要任何额外的细节。

    我一直相信,如果你能处理错误,就要避免异常——因为它已经不再是异常了,但我想知道关于避免重复自己的看法……你可以这样做,以避免重复你自己…

    try {    
        if (success) {
            return someSuccessMessage;
        }
        else {
            throw new Exception("User input not correct format");
        }
    }
    catch (Exception ex) {
        logError(ex.Message);
        return someErrorMessage;
    }
    

    这并不是最好的例子,但我想用简洁的方式来强调重复代码的重要性。

    众所周知,例外情况会导致性能损失,但对于这种情况有什么想法?

    6 回复  |  直到 17 年前
        1
  •  4
  •   John Saunders    17 年前

    我对这里关注点的分离表示怀疑。除非此函数是ui的一部分,否则它本身不应该关注错误消息。它 应该 而是抛出异常。此方法的调用方(如果它是ui的一部分)可能希望生成一条错误消息以供显示。如果调用者是一个web服务,那么它将希望产生一个soap错误,这个错误可能不使用相同的消息(如果它使用了任何消息)。

    我还强烈建议您记录ex.tostring()而不是ex.message。

        2
  •  3
  •   Adrian Godong    17 年前

    在imo中,只有在异常不在可纠正的情况下才应引发异常。用户输入的格式不正确是已知的,不应引发任何异常。

    将异常视为灾难性的(数据中心着火、地震等)。这样,您将看到处理“常规错误”和“异常”之间的区别。

    是的,抛出和捕获异常会消耗大量性能,最好是避免它们。

        3
  •  2
  •   dave4420    17 年前

    如果您觉得重复自己是个问题,请将重复的代码提取到函数中。

    error_code_t fail (string message) {
        logError(message);
        return someErrorMessage;
    }
    
    // ...
    
    try {    
        if (success) {
            return someSuccessMessage;
        }
        else {
            return fail("User input not correct format");
        }
    }
    catch (Exception ex) {
        return fail(ex.Message);
    }
    

    老实说,我不担心在同一个函数中重复几行。

        4
  •  1
  •   Grzenio    17 年前

    在您的例子中,我只返回错误消息(第一个例子),因为抛出一个异常仅仅是为了捕获它下面的3行似乎有点奇怪。

    另一件完全不同的事情是,我通常在可能的情况下避免返回错误代码——当我遇到错误情况时,我会通过一个异常,并在可能的最高级别捕获它。这样代码就不会到处乱放错误处理,更容易看到业务逻辑。在您的情况下(当然,如果您控制了它),返回success的方法可能在失败时抛出异常,您根本不必问这个问题:)

    诚然,在c_中,异常是昂贵的,因此它们不应该被滥用。话虽如此,当出现错误时,50ms左右的命中率通常是无关紧要的,所以我倾向于使用它们来保持代码的干净。

        5
  •  1
  •   Philip    17 年前

    我同意您在示例中的逻辑,但是您认为您在异常处理块中处理的异常与编程测试中处理的异常是什么?我怀疑你的异常处理块真的是“以防万一”。所以它实际上归结为异常处理规则。

    如果不需要处理异常,并且它不跨越不同的体系结构边界,则不需要处理它。如果它位于组件边界的边缘,则可能需要将其包装,将原始对象放置在内部异常中。

    如果从代码中调用该功能,则您可能希望使用某些状态表示(如响应)测试结果(hresult是其中的一个主要示例)。0==成功,!=0==失败)或使用异常。

    测试编程错误或组件失败是使用异常的地方,如果您在ui上验证来自用户的输入,您可能只想使用逻辑和返回状态代码来帮助将错误传达给用户。

    最后还要考虑本地化。如果您将一条英语错误消息通过系统向上发送,并将其呈现给讲法语的用户,这将是无用的,并且您不想在ui上开始解析字符串以生成法语版本,那么只要异常的有效负载有足够的信息来生成有用的错误消息,就可以使用异常。用户采取纠正措施。

    在组件和调用组件之间有紧密耦合的情况下使用状态代码,调用组件知道如何在不同的状态条件下执行操作。

    顺便说一下,您可能希望使用tostring()记录堆栈跟踪以及消息,因为它将为您提供解决问题的更多有用信息。

    高温高压

        6
  •  0
  •       17 年前

    在这种情况下,我实际上会说try/catch是不必要的,因为if可以更充分地处理您的错误

    但最底层的是我认为应该用于更复杂情况的风格

    推荐文章