Интересная мысль о рефакторинге кода, который возвращает ноль - PullRequest
0 голосов
/ 21 апреля 2011

Мне интересно услышать ваши отзывы. Недавно я видел некоторый код 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
}

Меня всегда беспокоит всякий раз, когда возвращается ноль без контекста. Я бы предпочел, чтобы ответ от SomeMethod был более явным и рассматривал возможность его рефакторинга. Создание исключения из SomeMethod может предложить способ сделать это. Это будет в контексте и произойдет в точке отказа.

Мне интересно, есть ли другой способ, где SomeMethod мог бы сообщить AnotherMethod, что «ничего не найдено в базе данных», вместо того, чтобы предполагать, что null всегда равняется «not found» Я думал, что можно использовать NullObject, но мне неясно, как AnotherMethod должен избегать «продолжения работы», если данные не были найдены.

Как бы вы изменили код?

Ответы [ 3 ]

2 голосов
/ 21 апреля 2011

Нулевой объект - это не конец всему. Это подходит для некоторых случаев (Collections.emptyXXX () является хорошим примером этого), но иногда вы должны различать что-то и ничего. Если возвращение ничего не является допустимым состоянием, то оно должно вернуть ноль.

Исключения составляют исключительные случаи, то есть то, что не должно происходить при нормальных обстоятельствах. Поймать и обработать исключения намного сложнее, чем проверка на ноль.

2 голосов
/ 21 апреля 2011

Я не вижу в этом проблемы, за исключением того, что я четко задокументировал бы, что SomeMethod может возвращать ноль в некоторых случаях.

Тем не менее, если обнаружение нулевого значения является явно исключительным случаем, то выбрасывание исключения является правильным подходом. Если вы измените AnotherMethod так, чтобы оно объявляло проверенное исключение, то ваши намерения были бы намного понятнее пользователям этого метода. Как то так:

void AnotherMethod() throws SomethingBadHappenedException {
  //snip
}
0 голосов
/ 21 апреля 2011

Однажды я работал над проектом, в котором результаты запросов были очень естественными. Но были особые случаи, когда коллекция должна быть пустой; другие случаи, когда коллекция должна содержать ровно один элемент.

Эти запросы выполнялись для объектов, которые иногда требовали сбоя в базе данных.

Подход, к которому мы наконец-то сошлись, заключался в том, чтобы возвращать результаты в нашем собственном типе (в отличие от 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

...