例如,我需要使用getFoo()方法获取Foo对象:
Foo foo = getFoo();
在此之后,我想处理getFoo()没有成功返回Foo对象的情况。这又包括两种情况:
理想情况下,我希望getFoo()抛出一个异常而不是返回一个空结果,但有时这可能是对另一个我不拥有的包中的方法的调用。
这些是我能想到的方法:
Foo foo = null;
try {
foo = getFoo();
} catch (ResourceNotFoundException ex) {
logger.warn("blablabla");
foo = defaultFoo;
someOtherComplicatedStuff();
}
if (null == foo) {
logger.warn("blablabla");
foo = defaultFoo;
someOtherComplicatedStuff();
}
这绝对不是一个好主意。
Foo foo = null;
try {
foo = getFoo();
} catch (ResourceNotFoundException ex) {
handleNullFoo(var1, var2, var3, var4);
}
if (null == foo) {
handleNullFoo(var1, var2, var3, var4);
}
问题是逻辑可能会使用很多局部变量。将这些变量传递给外部函数没有多大意义。更糟糕的是,在此过程中可能需要修改某些变量。我不认为修改函数中的参数是一种好的做法,更不用说如果参数是原始类型的话可能会导致的问题。
Foo foo = null;
try {
foo = getFoo();
if (null == foo) {
throw new ResourceNotFoundException();
}
} catch (ResourceNotFoundException ex) {
logger.warn("blablabla");
foo = defaultFoo;
someOtherComplicatedStuff();
}
这是迄今为止最干净的方式,但它更像是一种黑客行为。在异常类不属于的包中抛出ResourceNotFoundException可能不合适。它还降低了代码的可读性,因为人们可能没有意识到异常是在函数内部处理的。
那么,你的建议是什么?
非常感谢!
答案 0 :(得分:3)
这是另一种选择:
Foo foo = null;
try {
foo = getFoo();
} catch (ResourceNotFoundException ex) {
//TODO: log exception?
foo = null;
}
if (null == foo) {
logger.warn("blablabla");
foo = defaultFoo;
someOtherComplicatedStuff();
}
请注意,foo = null;
子句中的catch
几乎肯定是不必要的。只有foo = getFoo()
之后的某些代码可以抛出ResourceNotFoundException
时才需要它。
答案 1 :(得分:3)
怎么样?
class WrappedFooFactory extends FooFactory {
public foo tryGetFoo() throws ResourceNotFoundException {
Foo foo = getFoo();
if (null == foo) throw new ResourceNotFoundException();
return foo;
}
}
以后只是
Foo foo = null;
try {
foo = tryGetFoo();
} catch (ResourceNotFoundException ex) {
logger.warn("blablabla");
foo = defaultFoo;
someOtherComplicatedStuff();
}
答案 2 :(得分:2)
这样的替代方案呢?它更常见,适用于其他类似案例。
1)创建静态方法:
public static <E> E wrapNulls(Callable<E> callable, E defaultValue) {
E result = null;
try {
result = callable.call();
} catch (Exception e) {
// log exception
}
return result == null ? defaultValue : result;
}
2)以这种风格获取对象:
Foo foo = wrapNulls(new Callable<Foo>() {
@Override
public Foo call() throws Exception {
return getFoo();
}
}, defaultValue);
UPD:对于那些人来说,考虑到这段代码有点冗长,我可以建议这样的增强:
3)创建静态类:
static abstract class C<E> implements Callable<E> {
public abstract E c();
@Override
public E call() throws Exception {
return c();
}
}
并使用它而不是Callable
interface:
4)
Foo foo = wrapNulls(new C<Foo>() {public Foo c() { return getFoo(); }}, defValue);
答案 3 :(得分:0)
版本3是迄今为止最糟糕的! (不是最干净的!) 不要使用Exceptions进行流量控制!
它取决于应用程序的一点但是1是最好的,因为, 你可以并且通常会有两个不同的日志语句:
Foo foo = null;
try {
foo = getFoo();
} catch (ResourceNotFoundException ex) {
logger.warn("Foo: ", ex);
foo = defaultFoo;
someOtherComplicatedStuff();
}
if (null == foo) {
logger.warn("Foo: Got unexpected null");
foo = defaultFoo;
someOtherComplicatedStuff();
}