3

例如,我需要使用 getFoo() 方法获取一个 Foo 对象:

Foo foo = getFoo();

在此之后,我想处理 getFoo() 没有成功返回 Foo 对象的情况。这又包括两种情况:

  1. getFoo() 抛出异常。
  2. getFoo() 的返回结果为 null、空字符串、0 或任何应视为“空结果”的内容。

理想情况下,我希望 getFoo() 抛出异常而不是返回空结果,但有时这可能是对我不拥有的另一个包中的方法的调用。

这些是我能想到的方法:

1.重复处理代码

Foo foo = null;
try {
    foo = getFoo();
} catch (ResourceNotFoundException ex) {
    logger.warn("blablabla");
    foo = defaultFoo;
    someOtherComplicatedStuff();
}
if (null == foo) {
    logger.warn("blablabla");
    foo = defaultFoo;
    someOtherComplicatedStuff();
}

这绝对不是一个好主意。

2. 将处理逻辑移至单个函数

Foo foo = null;
try {
    foo = getFoo();
} catch (ResourceNotFoundException ex) {
    handleNullFoo(var1, var2, var3, var4);
}
if (null == foo) {
    handleNullFoo(var1, var2, var3, var4);
}

问题是逻辑可能会使用很多局部变量。将这些变量传递给外部函数没有多大意义。更糟糕的是,在此过程中可能需要修改一些变量。我不认为修改函数中的参数是一个好习惯,更不用说如果参数是原始类型可能导致的问题。

3. 抛出假异常

Foo foo = null;
try {
    foo = getFoo();
    if (null == foo) {
        throw new ResourceNotFoundException();
    }
} catch (ResourceNotFoundException ex) {
    logger.warn("blablabla");
    foo = defaultFoo;
    someOtherComplicatedStuff();
}

这是迄今为止最干净的方式,但它更像是一种 hack。在异常类不属于的包中抛出 ResourceNotFoundException 可能不合适。它还降低了代码的可读性,因为人们可能没有意识到异常是在函数内部处理的。

那么,你的建议是什么?

非常感谢你!

4

4 回答 4

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;incatch子句几乎可以肯定是不必要的。foo = getFoo()仅当之后有一些代码可以 throw时才需要它ResourceNotFoundException

于 2013-01-17T20:23:22.670 回答
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();
}
于 2013-01-17T20:25:31.477 回答
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接口:

4)

Foo foo = wrapNulls(new C<Foo>() {public Foo c() { return getFoo(); }}, defValue);
于 2013-01-17T20:31:19.450 回答
0

版本 3 是迄今为止最糟糕的!(不是最干净的!)不要使用异常进行流量控制!

它依赖于一些应用程序,但 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();
}
于 2013-01-17T20:25:04.863 回答