首页 文章

检索方法是否应返回'null'或在无法产生返回值时抛出异常? [关闭]

提问于
浏览
454

我有一个方法,如果找到它,它应该返回一个对象 .

如果找不到,我应该:

  • 返回null

  • 抛出异常

  • 其他

30 回答

  • 1

    如果您总是希望找到一个值,那么抛出异常(如果缺少) . 例外意味着存在问题 .

    如果值可能丢失或存在且两者都对应用程序逻辑有效,则返回null .

    更重要的是:你在代码中的其他地方做了什么?一致性很重要 .

  • 4

    如果确实是错误,则仅抛出异常 . 如果对象的预期行为不存在,则返回null .

    否则这是一个偏好的问题 .

  • 13

    作为一般规则,如果方法应始终返回一个对象,那么请使用异常 . 如果您预计偶尔出现null并希望以某种方式处理它,请使用null .

    无论你做什么,我都强烈反对第三种选择:返回一个写着“WTF”的字符串 .

  • 18

    如果null从不指示错误,则返回null .

    如果null始终是错误,则抛出异常 .

    如果null有时是异常,则代码编写两个例程 . 一个例程抛出异常,另一个是布尔测试例程,它返回输出参数中的对象,如果找不到对象,则例程返回false .

    很难滥用Try例程 . 忘记检查null是很容易的 .

    所以当null是一个错误你只需写

    object o = FindObject();
    

    当null不是错误时,您可以编写类似的代码

    if (TryFindObject(out object o)
      // Do something with o
    else
      // o was not found
    
  • 2

    我只是想概括一下前面提到的选项,抛出一些新的:

    • 返回null

    • 抛出异常

    • 使用null对象模式

    • 为您提供一个布尔参数方法,因此调用者可以选择是否要求您抛出异常

    • 提供了一个额外的参数,因此调用者可以设置一个值,如果没有找到值,他将返回该值

    或者您可以组合这些选项:

    提供几个重载版本的getter,这样调用者就可以决定走哪条路 . 在大多数情况下,只有第一个具有搜索算法的实现,而其他的只是包围第一个:

    Object findObjectOrNull(String key);
    Object findObjectOrThrow(String key) throws SomeException;
    Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
    Object findObjectOrDefault(String key, Object defaultReturnValue);
    

    即使您选择只提供一个实现,您也可能希望使用这样的命名约定来阐明您的 Contract ,如果您决定添加其他实现,它也会有所帮助 .

    你不应该过度使用它,但它可能是有帮助的,特别是在编写一个帮助程序类时,你将在数百种不同的应用程序中使用它们,它们具有许多不同的错误处理约定 .

  • 2

    使用null对象模式或抛出异常 .

  • 0

    与您正在使用的API保持一致 .

  • 93

    只要问自己:“这是一个特殊情况,没有找到对象”?如果预计会在程序的正常过程中发生,那么您可能不应该引发异常(因为它不是异常行为) .

    简短版本:使用异常来处理异常行为,而不是处理程序中的正常控制流 .

    -Alan .

  • 441

    这取决于你的语言和代码是否有所提升:LBYL(在你跳跃之前看)或EAFP(更容易请求宽恕而不是许可)

    LBYL说你应该检查值(所以返回null)
    EAFP说只是尝试操作并查看它是否失败(抛出异常)

    虽然我同意上述..异常应该用于异常/错误条件,并且在使用检查时返回null是最好的 .


    EAFP与Python中的LBYL:
    http://mail.python.org/pipermail/python-list/2003-May/205182.htmlWeb Archive

  • 63

    抛出异常的优点:

    • Cleaner control flow in your calling code. 检查null会注入一个由try / catch本机处理的条件分支 . 检查null是否't indicate what it is you'重新检查 - 您是否因为're looking for an error you'期待而检查是否为null,或者您是否正在检查null,因此您不会在下行链路上进一步传递它?

    • Removes ambiguity of what "null" means. null是否代表错误或为null实际存储在值中的是什么?很难说什么时候你只有一件事可以作出决定 .

    • Improved consistency between method behavior in an application. 异常通常在方法签名中公开,因此您更能够了解应用程序中的方法占用的边缘情况,以及应用程序可以以可预测的方式响应的信息 .

    有关示例的更多说明,请参阅:http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/

  • 4

    例外与 Contract 设计有关 .

    对象的接口实际上是两个对象之间的 Contract ,调用者必须满足 Contract ,否则接收者可能会失败并出现异常 . 有两种可能的 Contract

    1)所有输入方法都有效,在这种情况下,必须在找不到对象时返回null .

    2)只有一些输入是有效的,即导致找到对象的输入 . 在这种情况下,您必须提供允许调用者的第二种方法确定其输入是否正确 . 例如

    is_present(key)
    find(key) throws Exception
    

    IF和ONLY如果您同时提供第二份 Contract 的两种方法,您可以抛出异常,因为没有找到任何东西!

  • 1

    我更喜欢只返回一个null,并依赖调用者来适当地处理它 . (因为没有更好的词)例外是如果我绝对'确定'这个方法将返回一个对象 . 在这种情况下,失败是一种特殊的应该而且应该抛出 .

  • 3

    取决于找不到对象的含义 .

    如果它是正常的事务状态,则返回null . 这只是偶尔会发生的事情,并且呼叫者应该检查它 .

    如果它是一个错误,然后抛出异常,调用者应该决定如何处理丢失对象的错误条件 .

    最终要么会工作,尽管大多数人一般都认为只有在出现异常情况时才使用例外是一种好习惯 .

  • 1

    以下是一些建议 .

    如果返回一个集合,避免返回null,返回一个空集合,这使得枚举更容易处理,而不首先进行空检查 .

    几个.NET API使用thrownOnError参数的模式,该参数为调用者提供了选择,如果找不到该对象,它是否真的是异常情况 . Type.GetType就是一个例子 . BCL的另一个常见模式是TryGet模式,其中返回一个布尔值,并通过输出参数传递该值 .

    您还可以在某些情况下考虑Null对象模式,这些情况可以是默认值,也可以是没有行为的版本 . 关键是避免在整个代码库中进行空值检查 . 有关更多信息,请参见此处http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx

  • 1

    在一些函数中我添加一个参数:

    ..., bool verify = true)
    

    True表示throw,false表示返回一些错误返回值 . 这样,使用此功能的人都有两种选择 . 默认值应为true,以免忘记错误处理的人员 .

  • 47

    返回null而不是抛出异常,并清楚地记录API文档中返回值为null的可能性 . 如果调用代码不遵守API并检查null情况,那么它很可能会导致某种“空指针异常”:)

    在C中,我可以想到设置查找对象的方法的3种不同风格 .

    Option A

    Object *findObject(Key &key);
    

    无法找到对象时返回null . 很好,很简单 . 我会选择这个 . 以下替代方法适用于不讨厌外行的人 .

    Option B

    void findObject(Key &key, Object &found);
    

    传递对将接收对象的变量的引用 . 当无法找到对象时,该方法抛出异常 . 这个约定可能更合适,如果没有找到一个没有找到的对象 - 因此你抛出一个异常来表示它是一个意外的情况 .

    Option C

    bool findObject(Key &key, Object &found);
    

    无法找到对象时,该方法返回false . 这个优于选项A的优点是您可以在一个明确的步骤中检查错误情况:

    if (!findObject(myKey, myObj)) { ...
    
  • 2

    仅指null不被视为异常行为的情况我绝对是try方法,很明显,不需要“读书”或“在你跳跃之前看”如此处所述

    所以基本上:

    bool TryFindObject(RequestParam request, out ResponseParam response)
    

    这意味着用户的代码也将清晰

    ...
    if(TryFindObject(request, out response)
    {
      handleSuccess(response)
    }
    else
    {
      handleFailure()
    }
    ...
    
  • 1

    如果客户端代码知道找到和未找到之间的区别很重要并且这应该是常规行为,那么最好返回null . 然后,客户端代码可以决定要做什么 .

  • 11

    通常它应该返回null . 调用该方法的代码应该决定是抛出异常还是尝试别的东西 .

  • 3

    或者返回一个选项

    选项基本上是一个容器类,它强制客户端处理booth案例 . Scala有这个概念,查找它的API .

    然后你就可以在这个对象上使用T getOrElse(T valueIfNull)这样的方法来返回找到的对象,或者替换客户端指定的方法 .

  • 11

    只要它应该返回对象的引用,返回NULL应该是好的 .

    然而,如果它返回了整个血腥的东西(比如在C中,如果你这样做:'返回blah;'而不是'return&blah;'(或'blah'是指针),那么你不能返回NULL,因为它是不是'对象'类型 . 在这种情况下,抛出异常,或返回一个没有设置成功标志的空白对象是我如何处理问题 .

  • 1

    不要以为有人提到异常处理的开销 - 需要额外的资源来加载和处理异常,所以除非真正的应用程序查杀或进程停止事件(前进会造成弊大于利)我会选择传回一个调用环境可以根据需要解释的 Value .

  • 5

    我同意这里似乎达成的共识(如果“未找到”是正常的可能结果,则返回null,或者如果,则抛出异常)情境的语义要求始终找到对象) .

    但是,根据您的具体情况,第三种可能性是有意义的 . 您的方法可以在“未找到”条件下返回某种类型的默认对象,允许调用代码以确保它始终接收有效对象而无需空检查或异常捕获 .

  • 4

    返回null,异常就是这样:代码执行的操作不是预期的 .

  • 1

    例外情况应为 exceptional . 返回null if it is valid to return a null .

  • 23

    更喜欢返回null -

    如果调用者在没有检查的情况下使用它,则无论如何都会发生异常 .

    如果来电者没有 try / catch 阻止他

  • 3

    不幸的是,JDK是不一致的,如果您尝试访问资源包中的非现有密钥,则不会发现异常,并且当您从map请求值时,如果它不存在,则为null . 所以如果找到的值可以为null,那么我会将获胜者的答案更改为以下内容,然后在找不到时引发异常,否则返回null . 所以遵循规则有一个例外,如果你需要知道为什么找不到值然后总是引发异常,或者..

  • 1

    如果该方法返回一个集合,则返回一个空集合(如上所述) . 但请不要Collections.EMPTY_LIST等! (在Java的情况下)

    如果方法重新生成单个对象,那么您有一些选项 .

    • 如果方法总是应该找到结果并且它是一个真正的例外情况而不是找到对象,那么你应该抛出一个异常(在Java中:请一个未经检查的异常)

    • (仅限Java)如果您可以容忍该方法抛出已检查的异常,则抛出项目特定的ObjectNotFoundException等 . 在这种情况下,如果您忘记处理异常,编译器会告诉您 . (这是我首选处理Java中未找到的东西 . )

    • 如果你说它确实没问题,如果没有找到对象,你的方法名称就像findBookForAuthorOrReturnNull(..),那么你可以返回null . 在这种情况下,强烈建议使用某种静态检查或编译器检查,以防止在没有空检查的情况下取消引用结果 . 在Java的情况下,它可以是例如 . FindBugs(参见http://findbugs.sourceforge.net/manual/annotations.html的DefaultAnnotation)或IntelliJ-Checking .

    如果您决定返回null,请注意 . 如果您不是项目中唯一的程序员,您将在运行时获得NullPointerExceptions(使用Java或其他语言中的任何语言)!所以不要返回在编译时未检查的空值 .

  • 1

    如果您正在使用库或其他引发异常的类,那么您应该 rethrow 它 . 这是一个例子 . Example2.java就像库,Example.java使用它的对象 . Main.java是处理此异常的示例 . 您应该向主叫方的用户显示有意义的消息和(如果需要)堆栈跟踪 .

    Main.java

    public class Main {
    public static void main(String[] args) {
        Example example = new Example();
    
        try {
            Example2 obj = example.doExample();
    
            if(obj == null){
                System.out.println("Hey object is null!");
            }
        } catch (Exception e) {
            System.out.println("Congratulations, you caught the exception!");
            System.out.println("Here is stack trace:");
            e.printStackTrace();
        }
    }
    }
    

    Example.java

    /**
     * Example.java
     * @author Seval
     * @date 10/22/2014
     */
    public class Example {
        /**
         * Returns Example2 object
         * If there is no Example2 object, throws exception
         * 
         * @return obj Example2
         * @throws Exception
         */
        public Example2 doExample() throws Exception {
            try {
                // Get the object
                Example2 obj = new Example2();
    
                return obj;
    
            } catch (Exception e) {
                // Log the exception and rethrow
                // Log.logException(e);
                throw e;
            }
    
        }
    }
    

    Example2.java

    /**
     * Example2.java
     * @author Seval
     *
     */
    public class Example2 {
        /**
         * Constructor of Example2
         * @throws Exception
         */
        public Example2() throws Exception{
            throw new Exception("Please set the \"obj\"");
        }
    
    }
    
  • 6

    这实际上取决于你是否期望找到对象 . 如果你遵循思想学派,应该使用例外来表示某些东西,那么,错误,异常已经发生了:

    找到

    • 对象;返回对象

    • 未找到对象;抛出异常

    否则,返回null .

相关问题