典型的Java方法如下所示:
public <U,V> U doSomething(V aReference) {
// Do something
}这通常意味着,如果方法doSomething()失败(无论出于何种原因)或有效的对象引用,它将返回一个null。在某些情况下,“有效对象引用”本身可能是null。例如,方法aMap.get(k)可能返回null,如果没有键k,或者如果有键k,但对应的值是null。混乱!
更别提NullPointerException了,如果50%的LOC不仅仅是空检查的话。
像这样的方法有什么问题:
public <T> ReturnTuple<T> doSomething(V aReference) {
T anotherObjRef = getValidObjT();
if (successful) {
return ReturnTuple.getSuccessTuple(anotherObjRef);
} else {
return ReturnTuple.getFailureTuple("aReference can't be null");
}
}其中定义了类ReturnTuple<T>,如下所示:
class ReturnTuple<T> {
private boolean success;
// Read only if success == true
private T returnValue;
// Read only if success == false
private String failureReason;
// Private constructors, getters, setters & other convenience methods
public static <T> ReturnTuple<T> getSuccessTuple(T retVal) {
// This code is trivial
}
public static <T> ReturnTuple<T> getFailureTuple(String failureReason) {
// This code is trivial
}
}然后调用代码将如下所示:
ReturnTuple<T> rt = doSomething(v);
if (rt.isSuccess()) {
// yay!
} else {
// boo hoo!
}所以,我的问题是:为什么这种模式不更常见?这是怎么回事?
请记住,我要求的不是对这个精确代码的批评,而是对这个总体想法的批评。
请注意:这里的要点不是让上面的代码编译,只是为了讨论一个想法。所以,请不要对代码的正确性过于迂腐:-)。
编辑1:动机
我想我应该从一开始就增加这一节,但迟到总比不.
IllegalArgumentException这样的异常),谨慎地记录失败原因(而不是隐藏异常的丑陋堆栈跟踪),并且只让调用者使用所需的确切信息。这也促进了信息隐藏和封装。这种想法并非完全没有价值,因为Java 8提供了可选类(正如@JBNizet所指出的那样),而谷歌的番石榴库也有一个可选类。这只会让事情进一步发展。
发布于 2014-07-05 11:08:36
这通常意味着如果方法
doSomething()失败,它将返回null。
不,这并不意味着。这意味着doSomething()方法有时可以合法地返回null,而不会失败。Java为处理故障提供了一个强大的系统,即异常处理。这就是API应该如何指示失败的方式。
为什么这种返回元组模式不更常见呢?这是怎么回事?
这种模式的主要错误之处在于它使用了一种与Java无关的报告失败的机制。如果您的API运行失败,抛出一个异常。这样可以避免在“主流”情况下创建两倍于所需的对象,并使您的API能够直观地为熟悉Java类库的人所理解。
在有些情况下,返回null可以被解释为两种方式--失败和合法的返回值。在关联容器中查找对象提供了一个很好的例子:当您提供一个不在映射中的键时,您可以声称这是一个编程错误,并抛出一个异常(.NET类库这样做),或者声称当键丢失时,映射中相应的位置包含默认值,即null --这是在Java中这样做的。在这种情况下,返回一个元组是完全可以接受的。Java的Map决定不这样做,很可能会在每次从Map请求对象时节省创建额外的对象。
https://stackoverflow.com/questions/24585677
复制相似问题