0

我有兴趣听到您的反馈。我最近看到了一些以下列方式实现的 Java 代码:

Object1 SomeMethod(String key) {
    Object1 object1 = null;
    List<Object1> objectList = getAllRecordsWithKeyFromDatabase(key);
    if (!objectList.isEmpty()) {
        object1 = objectList.get(0);
    }
    return object1;
}

void AnotherMethod() {
    ...
    Object1 object1 = SomeMethod(key);
    if (object1 == null) {
        // throw exception
    }
    // continue working
}

每当在没有上下文的情况下返回 null 时,我总是很担心。我希望 SomeMethod 的响应更明确,并正在考虑对其进行重构。从 SomeMethod 抛出异常可以提供一种方法来做到这一点。它将在上下文中发生并发生在故障点。

我想知道 SomeMethod 是否有另一种方式可以通知 AnotherMethod '在数据库中没有找到任何东西',而不是假设 null 总是等于'未找到'。我认为可以使用 NullObject,但我不清楚如果找不到数据,AnotherMethod 应该如何避免“继续工作”。

你将如何重构代码?

4

3 回答 3

2

我认为它没有问题,只是我会清楚地记录SomeMethod在某些情况下可以返回 null 。

但是,如果找到 null 显然是一个例外情况,那么抛出异常是正确的方法。如果您进行更改AnotherMethod以声明一个已检查的异常,那么您的意图对于该方法的用户来说会更加清晰。像这样的东西:

void AnotherMethod() throws SomethingBadHappenedException {
  //snip
}
于 2011-04-21T17:50:59.450 回答
2

空对象不是全部结束。它适用于某些情况(Collections.emptyXXX() 就是一个很好的例子),但有时你必须区分什么和什么都没有。如果什么都不返回是一个有效的状态,那么它应该返回 null。

例外是针对例外情况,即在正常情况下不应该发生的事情。捕获和处理异常比检查 null 要困难得多。

于 2011-04-21T17:52:48.080 回答
0

我曾经在一个项目中工作,其中查询结果非常自然地是集合。但是有一些特殊情况,集合应该是空的;集合应仅包含一个元素的其他情况。

这些查询是在有时需要从数据库中出错的对象上执行的。

我们最终采用的方法是将返回的结果包装在我们自己的类型中(而不是 ArrayList 之类的)。为了显示:

public interface Results<T> implements Iterable<T> {
  Collection<T> all();
  Iterator<T> iterator();
  /**
   * @return one value from the result, or null if the result is empty.
   */
  T ifAny();

  /**
   * @return one value from the result.
   */
  T one() throws EmptyResultException;

  /**
   * @return if the result is empty, returns null, 
   *         if the result has one value, returns the value,
   *         if the result has more than one value, throws.
   */
  T unique() throws MultiValueResultException;

  /**
   * @return the value if the result has exactly one; throws otherwise
   */
  T exact() throws NoExactResultException;
}

如果语义对您很重要,您可以在您的情况下使用类似的方法:

public final class Result<T> {
  private static final Object NON = new Object();

  private final Object _value;

  public Result(T value) {
    if (value == null) {
      throw ...
    }
    _value = value;
  }

  public T get() {
    return (_value == NON) ? null : (T) _value;
  }

  public T use() {
    if (_value == NON) {
      throw ...
    }
    return (T) _value;
  }
}

请注意,Scala 习语使用 Option 来达到类似的效果。这是有关该主题的众多链接之一:http: //www.codecommit.com/blog/scala/the-option-pattern

于 2011-04-21T18:15:03.653 回答