检索方法应该返回'null'还是无法产生返回值时引发异常? [关闭]

已关闭 。 这个问题是 基于观点的 。 它当前不接受答案。

想改善这个问题吗? 更新问题,以便通过编辑此帖子以事实和引用的形式回答。

3年前关闭。

我有一种方法,应该在找到对象后返回它。

如果找不到,我应该:

  1. 返回null
  2. 抛出异常
  3. 其他

#1楼

如果该方法返回一个集合,则返回一个空集合(如上述)。 但请不要使用Collections.EMPTY_LIST之类的! (对于Java)

如果该方法检索单个对象,则您有一些选择。

  1. 如果该方法应始终找到结果,并且是找不到对象的真正异常情况,则应引发异常(在Java中:请未经检查的Exception
  2. (仅Java)如果可以忍受该方法引发检查异常,则引发项目特定的ObjectNotFoundException或类似事件。 在这种情况下,如果您忘记处理异常,编译器会告诉您。 (这是我对Java中找不到的东西的首选处理。)
  3. 如果您说没关系,如果找不到对象,并且您的方法名称类似于findBookForAuthorOrReturnNull(..),则可以返回null。 在这种情况下, 强烈建议您使用某种静态检查或编译器检查,以防止在没有空检查的情况下取消对结果的引用。 如果是Java,可以是例如。 FindBugs(请参阅http://findbugs.sourceforge.net/manual/annotations.html上的 DefaultAnnotation)或IntelliJ-Checking。

如果您决定返回null,请当心。 如果您不是项目中唯一的程序员,则在运行时将获得NullPointerExceptions(使用Java或其他语言)。 因此,请勿返回在编译时未检查的null。


#2楼

我更喜欢只返回一个null,然后依靠调用方对其进行适当处理。 (由于缺少更好的词)例外是,如果我绝对“确定”此方法将返回一个对象。 在那种情况下,失败是异常的,应该抛出。


#3楼

与您使用的API保持一致。


#4楼

使用空对象模式或引发异常。


#5楼

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


#6楼

通常,它应该返回null。 调用该方法的代码应决定是引发异常还是尝试其他事情。


#7楼

这实际上取决于您是否希望找到对象。 如果您遵循这样的学派,那就应该使用异常来表示某些东西,好吧,错了,异常发生了,那么:

  • 找到对象; 返回对象
  • 找不到对象; 抛出异常

否则,返回null。


#8楼

仅当确实是错误时才引发异常。 如果该对象的预期行为不存在,则返回null。

否则,这是一个优先事项。


#9楼

如果您一直期望找到一个值,那么如果缺少该值,则抛出异常。 例外意味着存在问题。

如果该值可能缺失或存在,并且对于应用程序逻辑均有效,则返回null。

更重要的是:您在代码的其他位置做什么? 一致性很重要。


#10楼

通常,如果方法应始终返回对象,则应使用异常。 如果您预计偶尔会出现null并希望以某种方式进行处理,请使用null。

无论您做什么,我都强烈建议不要使用第三个选项:返回一个表示“ WTF”的字符串。


#11楼

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

如果状态正常,则返回null。 这只是偶尔会发生的事情,呼叫者应进行检查。

如果是错误,则引发异常,调用者应决定如何处理丢失对象的错误情况。

最终,两者都会起作用,尽管大多数人通常认为,仅在发生异常的情况下才使用Exceptions是一种很好的做法。


#12楼

只要应该返回对对象的引用 ,则返回NULL应该很好。

但是,如果返回的是满是血腥的东西(例如在C ++中,如果您这样做:“ return blah;”而不是“ return&blah;”(或“ blah”是一个指针)),那么您将无法返回NULL,因为它是在这种情况下,抛出异常或返回没有设置成功标志的空白对象就是我要解决的问题。


#13楼

返回null而不是引发异常,并在API文档中清楚地记录了返回空值的可能性。 如果调用代码不支持API并检查null大小写,则很可能会导致某种“空指针异常” :)

在C ++中,我可以想到3种不同的方式来设置找到对象的方法。

选项A

Object *findObject(Key &key);

找不到对象时返回null。 漂亮又简单。 我会去的。 以下替代方法适用于不讨厌实物的人。

选项B

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

传递对将接收对象的变量的引用。 当找不到对象时,该方法引发异常。 如果不是真正希望找不到对象,则此约定可能更合适-因此,您抛出异常以表示这是意外情况。

选项C

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

当找不到对象时,该方法返回false。 与选项A相比,此选项的优势在于,您可以在一个清晰的步骤中检查错误情况:

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

#14楼

不要以为任何人都提到了异常处理的开销-需要额外的资源来加载和处理异常,因此,除非它是真正的应用程序终止或进程停止事件(前进会造成弊大于利),否则我会选择返回一个调用环境可以认为合适的值。


#15楼

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

但是,根据您的特定情况,存在第三种可能有意义的可能性。 您的方法可以在“未找到”条件下返回某种默认对象,从而确保调用代码可以始终收到有效对象,而无需进行空检查或异常捕获。


#16楼

如果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

#17楼

或退回期权

一个选项基本上是一个容器类,它迫使客户处理展位情况。 Scala有这个概念,请查询它的API。

然后,在该对象上具有T getOrElse(T valueIfNull)之类的方法,它们要么返回找到的对象,要么由客户指定。


#18楼

返回一个null,异常恰好是:您的代码执行了某些意外的操作。


#19楼

这取决于您的语言和代码是否能促进:LBYL(飞跃之前先看一下)或EAFP(更容易要求宽恕而不是允许)

LBYL说您应该检查值(因此返回null)
EAFP表示只需尝试操作,看看它是否失败(引发异常)

尽管我在上面也同意。.异常/错误条件应使用异常,使用检查时最好返回null。


EAFP与LBYL在Python中的比较:
http://mail.python.org/pipermail/python-list/2003-May/205182.html(Web 存档


#20楼

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

..., bool verify = true)

True表示抛出,false表示返回一些错误返回值。 这样,无论使用此功能的人都有两个选择。 默认值应为true,以使那些忘记错误处理的人受益。


#21楼

只是问问自己:“找不到对象是一种特殊情况吗?” 如果预期在程序的正常过程中发生这种情况,则可能不应引发异常(因为这不是异常行为)。

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

阿兰


#22楼

例外应该是例外如果可以返回null ,则返回null


#23楼

例外与按合同设计有关。

对象的接口实际上是两个对象之间的契约,调用者必须满足该契约,否则接收者可能会因异常而失败。 有两种可能的合同

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

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

is_present(key)
find(key) throws Exception

如果并且仅当您提供第二个合同的两种方法时,您才可以抛出异常,因为找不到任何东西!


#24楼

这里还有更多建议。

如果返回一个集合,请避免返回null,而返回一个空集合,这会使枚举更容易处理,而无需先执行null检查。

多个.NET API使用thrownOnError参数的模式,该模式使调用者可以选择是否找到对象是否真的是例外情况。 Type.GetType就是一个例子。 BCL的另一个常见模式是TryGet模式,其中返回一个布尔值,并且该值通过输出参数传递。

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


#25楼

如果您使用的是引发异常的库或其他类,则应将其重新抛出 。 这是一个例子。 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();
    }
}
}

范例.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\"");
    }

}

#26楼

我只是想概括一下前面提到的选项,并在其中添加一些新选项:

  1. 返回null
  2. 抛出异常
  3. 使用空对象模式
  4. 为您的方法提供布尔参数,以便调用者可以选择是否要引发异常
  5. 提供一个额外的参数,以便调用者可以设置一个值,如果找不到值,他将返回该值

或者您可以结合使用以下选项:

提供您的getter的多个重载版本,以便调用者可以决定要走的路。 在大多数情况下,只有第一个具有搜索算法的实现,而其他仅包含第一个:

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

即使您选择仅提供一个实现,也可能希望使用类似的命名约定来阐明您的合同,并且如果您决定还添加其他实现,则它可以帮助您。

您不应过度使用它,但它可能会有所帮助,尤其是在编写一个将在具有许多不同错误处理约定的数百个不同应用程序中使用的助手类时。


#27楼

仅仅指的是null不被认为是一种异常行为的情况,我肯定是使用try方法的,很明显,不需要像这里所说的那样“看书”或“在飞跃之前先看一下”

所以基本上:

bool TryFindObject(RequestParam request, out ResponseParam response)

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

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

#28楼

首选返回null-

如果调用者不经检查就使用它,则无论如何都会发生异常。

如果呼叫者没有真正使用它,请不要向他征税try / catch


#29楼

不幸的是,JDK是不一致的,如果您尝试访问资源束中不存在的键,则不会发现异常,并且当您从map请求值时,如果不存在该值,则会得到null。 因此,如果发现的值可以为null,则将优胜者答案更改为以下内容,如果找不到则引发异常,否则返回null。 因此,请遵循带有一个例外的规则,如果您需要知道为什么找不到值,请始终提出例外,或者。


#30楼

引发异常的优点:

  1. 您的调用代码中的控制程序更简洁。 检查是否为空会注入条件分支,该分支由try / catch本地处理。 检查null并不表示您要检查的是什么-您是否正在检查null是因为您正在寻找期望的错误,还是正在检查null,因此您不会在下链进一步传递它?
  2. 消除了“ null”的含义的歧义。 null代表错误还是null实际存储在值中? 很难说何时只有一件事可以基于这种决心。
  3. 改进了应用程序中方法行为之间的一致性。 异常通常在方法签名中公开,因此您更能够理解应用程序中方法所占的优势,以及应用程序可以以可预测的方式对哪些信息作出反应。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值