Подтвердить что ты не робот

Существует ли стандартный класс исключения java, который означает "Объект не найден"?

Рассмотрим функцию следующего общего вида:

Foo findFoo(Collection<Foo> foos, otherarguments)
throws ObjectNotFoundException {
    for(Foo foo : foos){
        if(/* foo meets some condition*/){
            return foo;
        }
    }
    throw new ObjectNotFoundException();
}

Например, конкретный случай:

User findUserByName(Collection<User> users, String name)
throws ObjectNotFoundException {
    for(User user : users){
        if(user.getName().equals(name)){
            return user;
        }
    }
    throw new ObjectNotFoundException();
}

Эти функции генерируют исключение, если объект не найден. Я могу создать для них специальный класс исключений (в примерах ObjectNotFoundException), но я бы предпочел использовать существующий класс. Однако я не смог найти класс исключения с этим значением в стандартной библиотеке java. Вы знаете, есть ли стандартное исключение, которое можно использовать здесь?

4b9b3361

Ответ 1

Знаете ли вы, существует ли стандартное исключение, которое можно использовать здесь?

Существует несколько исключений, которые могут быть использованы (например, NoSuchElementException или IllegalArgumentException), но ответ действительно зависит от семантики, которую вы собираетесь передать:

  • NoSuchElementException имеет тенденцию использоваться, когда вы выполняете последовательность или перечисление, где то, что у вас есть, - это поиск.

  • IllegalArgumentException имеет тенденцию подразумевать, что аргумент ошибочен, но в этом случае возможно, что допущения вызывающего пользователя неверны или что-то, что специфично для логики приложения.

  • Пользовательское исключение позволяет вам сказать (в javadocs) именно то, что означает исключение. Вы также можете объявить его проверенным... если это необходимо.

(Но не испытывайте соблазна использовать UnknownUserException. Это было бы ужасно неправильно, прочитайте javadoc!)


Также стоит подумать о возврате null, особенно если сбой поиска скорее всего будет довольно распространенным (не исключительным) событием в вашем приложении. Однако, обратная сторона возврата null заключается в том, что вызывающему абоненту необходимо проверить null или риск неожиданного NullPointerException s. В самом деле, я бы сказал, что чрезмерное использование null хуже, чем чрезмерное использование исключений. Первое может привести к ненадежным приложениям, тогда как последнее "плохо" для производительности.

Для Java 8 и далее возврат Optional будет более чистым выбором, чем возвращение null.


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

Ответ 2

Исключения создаются для обозначения исключительного поведения. По-моему, объект, не найденный, не является исключительным. Я бы переписал ваш метод, чтобы вернуть null, если пользователь не найден.

User findUserByName(Collection<User> users, String name) {
   for(User user : users){
       if(user.getName().equals(name)){
           return user;
      }
    }
  return null; 
}

Это стандартное поведение для многих коллекций Java. Например, http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#get(java.lang.Object) вернет значение null, если на карте нет записи с указанным ключом.

Вам следует избегать использования исключений в логике ваших программ.

Ответ 3

Это зависит от вашего документально оформленного контракта:

Если в вашей документации по методу указано, что аргумент name должен соответствовать имени существующего пользователя, тогда ему необходимо бросить IllegalArgumentException, если имя не найдено, поскольку это означает, что вызывающий пользователь нарушил требования метода передавая имя, которое не соответствует пользователю.

Если ваш метод не говорит, что имя должно соответствовать существующему пользователю, то передача неизвестного имени не является ошибкой, и вы не должны генерировать исключение вообще. Возврат null был бы уместным в этой ситуации.

Обратите внимание, что ваш метод findUserByName в основном заново изобретает метод Map.get, который возвращает null, если указанный ключ не является найдено.

Ответ 4

IllegalArgumentException иногда используется здесь, но использование вашего собственного Exception прекрасно.

В качестве альтернативы я рекомендую использовать карту с String name в качестве ключа и User в качестве значения. Итерация по коллекции тогда была бы ненужной, и это помешало бы двум пользователям с тем же именем в коллекции. Если вы не хотите использовать карту, то, по крайней мере, защитите ее от NullPointerException так:

User findUserByName(Collection<User> users, String name) throws ObjectNotFoundException
{
  if (name == null)
  {
    throw new IllegalArgumentException("name parameter must not be null");
  }
  if (users == null)
  {
    throw new IllegalArgumentException("Collection of users must not be null");
  }
  for(User user : users)
  {
    if(name.equals(user.getName()))
    {
      return user;
    }
  }
  throw new ObjectNotFoundException("Unable to locate user with name: " + name);
}

Ответ 5

С Java 8 я бы рекомендовал использовать опцию для этого варианта использования.

Optional<User> findUserByName(Collection<User> users, String name){
    Optional<User> value = users
        .stream()
        .filter(a -> a.equals(name))
        .findFirst();
}

Это также делает очень понятным для вызывающего, что необязательный может быть пустым, если значение не найдено. Если вы действительно хотите исключить исключение, вы можете использовать orElseThrows в опции "Дополнительно" для его достижения.