如何在Java中统一处理“异常或空”的情况?

时间:2013-01-17 20:19:43

标签: java

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

Foo foo = getFoo();

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

  1. getFoo()抛出异常。
  2. getFoo()的返回结果为null,空字符串,0或任何应被视为“空结果”的内容。
  3. 理想情况下,我希望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();
    }
    

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

    那么,你的建议是什么?

    非常感谢!

4 个答案:

答案 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();
}