我使用java语言,我有一个方法,如果它被找到,应该返回一个对象。

如果没有找到,我是否应该:

返回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);

即使您选择只提供一个实现,您也可能希望使用这样的命名约定来阐明您的契约,并且它有助于您决定添加其他实现。

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

其他回答

如果您总是希望找到一个值,那么如果缺少该值则抛出异常。这个例外意味着有问题。

如果该值可以缺失或存在,并且两者都对应用程序逻辑有效,则返回null。

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

这里还有一些建议。

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

一些. net API使用thrownOnError参数的模式,如果对象没有找到,调用者可以选择是否真的是异常情况。类型。GetType就是一个例子。BCL的另一个常见模式是TryGet模式,其中返回一个布尔值,并通过输出参数传递值。

在某些情况下,您还可以考虑Null Object模式,它可以是默认的,也可以是没有行为的版本。关键是避免在整个代码库中进行空检查。更多信息请参见这里链接

如果对于客户端代码来说,知道已找到和未找到之间的区别很重要,并且这应该是一个例程行为,那么最好返回null。然后客户端代码可以决定要做什么。

在数据层代码中,我有时使用以下代码,允许调用者决定“对象未找到”是否意味着发生了错误。


DataType GetObject(DBConnection conn, string id, bool throwOnNotFound) {
    DataType retval = ... // find object in database
    if (retval != null || ! throwOnNotFound) {
        return retval;
    } else {
        throw new NoRowsFoundException("DataType object with id {id} not found in database");
    }
}

DataType GetObject(DBConnection conn, string id) {
    return GetObject(conn, id, true);
} 

如果您正在使用抛出异常的库或其他类,则应该重新抛出异常。这里有一个例子。Example2.java类似于library,而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\"");
    }

}