关于返回 null 的重构代码的有趣思考问题

发布于 2024-11-03 01:37:57 字数 744 浏览 6 评论 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 应如何避免“继续工作”。

您将如何重构代码?

I am interested in hearing your feedback. I've recently seen some Java code that is implemented in the following way:

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
}

I am always concerned whenever a null is returned without context. I would rather the response from SomeMethod be more explicit and was considering refactoring it. Throwing an exception from SomeMethod could offer a way to do this. It would be in context and occur at the point of failure.

I am wondering if there is another way where SomeMethod could inform AnotherMethod that 'nothing was found in the database' instead of assuming that null always equaled 'not found'. I thought that a NullObject could be used, but it is unclear to me how AnotherMethod should avoid 'continue working' if the data was not found.

How would you refactor the code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冷弦 2024-11-10 01:37:57

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

但是,如果发现 null 显然是一种例外情况,那么抛出异常是正确的方法。如果您更改 AnotherMethod 以便它声明受检查的异常,那么您的意图对于该方法的用户来说会更加清晰。像这样的事情:

void AnotherMethod() throws SomethingBadHappenedException {
  //snip
}

I don't see a problem with it as it, except that I would clearly document that SomeMethod can return null in some cases.

However, if finding null is clearly an exceptional case, then throwing an exception is the right approach. If you change AnotherMethod so that it declares a checked exception, then your intent would be much clearer to users of that method. Something like this:

void AnotherMethod() throws SomethingBadHappenedException {
  //snip
}

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

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

Null object is not the be all end all. It is appropriate for some cases (Collections.emptyXXX() is a good example of this), but sometimes you have to distinguish between something and nothing. If returning nothing is a valid state, then it should return null.

Exceptions are for exceptional cases, i.e. things that should not happen under normal circumstances. Catching and handling exceptions is much more difficult than a check for null.

扎心 2024-11-10 01:37:57

我曾经参与过一个项目,其中查询结果非常自然地是集合。但在特殊情况下,集合应该为空;在其他情况下,集合应该只包含一个元素。

这些查询是在有时需要数据库故障的对象上执行的。

我们最终达成一致的方法是用我们自己的类型(而不是 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

I once worked on a project where query results were very naturally collections. But there were special cases where the collection should be empty; other cases where the collection should contain exactly one element.

These queries were being performed on objects that sometimes required faulting from a database.

The approach we finally converged upon was to have our results be returned wrapped in our own type (as opposed to ArrayList or something). To illustrate:

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;
}

You can use a similar approach in your case, if the semantics are important to you:

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;
  }
}

Note that Scala idioms use Option to similar effect. Here's one of many links on that side topic: http://www.codecommit.com/blog/scala/the-option-pattern

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文