是否有一个标准的Java异常类表示“找不到对象”?


77

考虑以下一般形式的函数:

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库中找不到具有此含义的任何异常类。您知道这里是否可以使用标准例外吗?


IlleagalArgumentException
Suresh Atta 2014年

当三行代码自己提供异常时,为什么您坚持要求JDK提供异常呢?我不知道您还要使用哪些API;JPA例如提供“ NoResultException”。
Gimby 2014年

我会去:IllegalArgumentException正如文档所说:Thrown to indicate that a method has been passed an illegal or inappropriate argument.实际上正在发生什么。
豪尔赫·坎波斯

4
恕我直言,最好创建与您的方法/类/图层/应用程序的上下文相关的自定义异常,但是如果您坚持可以使用NoSuchElementException
Svetlin Zarev,2014年

7
@Gimby在什么时候OP“坚持” JDK提供了异常?OP表示了偏爱,并提出了一个问题。而且,三行代码在得到适当记录后会变得更长。如果JDK已经提供了它,为什么还要麻烦呢?
2014年

Answers:


89

您知道这里是否可以使用标准例外吗?

有几个例外的是可以使用(例如NoSuchElementExceptionIllegalArgumentException),但答案实际上取决于你想要传达的语义:

  • NoSuchElementException 当您单步执行序列或枚举时,通常会使用其中的内容。

  • IllegalArgumentException 倾向于暗示参数是错误的,但是在这种情况下,可能是调用者的假设不正确,或者是应用程序逻辑所特有的。

  • 定制异常允许您(在javadocs中)确切地说出异常的含义。您也可以声明要检查...如果合适的话。

(但不要试图使用 UnknownUserException。那将是完全错误的;请阅读javadoc!)


还值得考虑返回null,尤其是在应用程序中查找失败很可能是相当普遍的事件(非异常)的情况下。 但是,返回的缺点null是呼叫者需要检查null或冒意外NullPointerException的风险。的确,我认为过度使用null比过度使用例外要糟。前者可能导致应用程序不可靠,而后者“仅”对性能不利。

对于Java 8及更高版本,返回Optionala比返回a更干净null


在这些情况下,重要的是要超越教条,并根据实际情况需要下定决心。


7

创建例外来标记异常行为。我认为,找不到对象的情况并非例外。如果找不到用户,我将重写您的方法以返回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,如果在指定键的条目中地图。

您应该避免在程序逻辑中依赖异常。


18
您怎么知道这不是例外?这取决于应用程序!抱歉,但是(除了循环逻辑之外)没有任何理由可以认为丢失用户永远不是例外情况。
Stephen C

7
null是邪恶的-如果可以使用Java 8,则应使用Optional该方法可能不返回所请求对象的名称(因此命名)。否则,这取决于。我更喜欢在公共方法中抛出异常并null在私有方法中返回。
Svetlin Zarev 2014年

1
@StephenC,您的意思是“取决于应用程序逻辑”-如我之前所写,使用异常创建应用程序逻辑被视为反模式。在这里阅读更多:programmers.stackexchange.com/questions/189222/...
MGorgon

6
IMO,情况是否异常取决于调用该方法的代码。如果传递的集合以包含元素的方式构造,则该对象不存在的事实应被视为异常。
2014年

2
@MGorgon-现在您正在求助于循环逻辑。该“异常不应该被用于应用程序逻辑”的教条假设有应用程序逻辑和处理例外事件之间有明显的区别。没有这种明显的区别。这是判断/见解的问题。
Stephen C

5

IllegalArgumentException 有时在这里使用,但是使用您自己的Exception完全可以。

顺便说一句,我建议使用MapString 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);
}

后期评论。是否应“捍卫”null和反对NPE尚有争议。另一种观点是,当将anull传递给未记录为allow的API方法时,则为nullBUG,并且抛出NPE(作为该条件的最具体例外)。完全防止NPE(例如,通过尝试“使好”)或抛出其他异常将无济于事,并且通过隐藏应引起开发人员/维护人员注意的问题,可能会使情况变得更糟。
Stephen C

在此示例中,如果您抛出NullPointerException或,则没有任何区别IllegalArgumentException。两者都是未经检查的异常,并且两者都应导致调用者使用堆栈跟踪来“纾困”,以供开发人员查看。因此,至少users == null检查是多余的。(NPE是您的朋友,而不是您的敌人!)
Stephen C

4

对于Java 8,我建议对此用例使用Optional。

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

这也使调用者很清楚,如果找不到该值,则可选参数可以为空。如果您确实想引发异常,则可以orElseThrows在Optional中使用它来实现。


3

这取决于您方法记录的接口协定:

如果您的方法的文档指出该name参数必须与现有用户的名称相对应,那么IllegalArgumentException如果找不到该名称,则应该抛出该异常,因为这意味着调用者通过传递与该名称不对应的名称而违反了该方法的要求。用户。

如果您的方法没有说名称必须与现有用户相对应,则传递未知名称不是错误,并且您根本不应抛出异常。null在这种情况下返回是合适的。

请注意,您的findUserByName方法基本上是在重新发明该Map.get方法,null如果找不到指定的键,则返回该方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.