是否有一个标准的Java异常类表示“找不到对象”?
考虑以下一般形式的函数:
Foo findFoo(Collection foos, otherarguments)
throws ObjectNotFoundException {
for(Foo foo : foos){
if(/* foo meets some condition*/){
return foo;
}
}
throw new ObjectNotFoundException();
}
例如,一个具体案例是:
User findUserByName(Collection users, String name)
throws ObjectNotFoundException {
for(User user : users){
if(user.getName().equals(name)){
return user;
}
}
throw new ObjectNotFoundException();
}
如果找不到对象,这些函数将引发异常。 为此,我可以创建一个自定义的异常类(在示例中为ObjectNotFoundException),但我希望使用现有的类。 但是,我在标准java库中找不到具有此含义的任何异常类。 您知道这里是否可以使用标准例外吗?
5个解决方案
63 votes
您知道这里是否可以使用标准例外吗?
可以使用几种例外情况(例如Optional或null),但答案确实取决于您要传达的语义:
当您单步执行一个序列或枚举时,通常会使用Optional,此处您需要的是查找。
Optional倾向于暗示该参数有误,但是在这种情况下,可能是调用者的假设不正确,或者是应用程序逻辑所特有的。
自定义异常允许您(在javadocs中)确切地说出异常的含义。 您也可以声明要检查...如果合适的话。
(但是请不要尝试使用Optional。那将是非常错误的;请阅读javadoc!)
还值得考虑返回Optional,特别是如果在您的应用程序中查找失败很可能是相当普遍的(非异常)事件时,尤其如此。 但是,返回null的不利之处在于,呼叫者需要检查null或冒意外的NullPointerExceptions的风险。 的确,我会争辩说,过度使用null比过度使用例外情况更糟糕。 前者可能导致应用程序不可靠,而后者“仅”对性能不利。
对于Java 8及更高版本,返回Optional比返回null更干净。
在这些情况下,重要的是要超越教条,并根据实际情况下定决心。
Stephen C answered 2020-01-12T01:25:57Z
6 votes
创建例外来标记异常行为。 我认为,找不到对象的情况并非例外。 如果找不到用户,我将重写您的方法以返回null。
User findUserByName(Collection 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。 在地图上。
您应该避免在程序逻辑中依赖异常。
MGorgon answered 2020-01-12T01:26:26Z
4 votes
有时在这里使用String name,但是使用您自己的Exception很好。
顺便说一句,我建议使用一个Map,键为2698694077117117367296,键值为User。 这样就不需要对集合进行迭代,并且可以防止集合中有两个具有相同名称的用户。 如果您不想使用地图,那么至少要像这样防御NullPointerException:
User findUserByName(Collection 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);
}
Paul answered 2020-01-12T01:26:51Z
3 votes
这取决于您方法记录的接口协定:
如果您的方法的文档指出Map.get参数必须与现有用户的名称相对应,那么如果找不到该名称,则抛出null是适当的,因为这意味着调用者通过传递一个名称而不符合方法要求的名称 对应一个用户。
如果您的方法没有说名称必须与现有用户相对应,则传递未知名称不是错误,并且您根本不应抛出异常。 在这种情况下,返回Map.get是合适的。
请注意,您的2698694694292292987392方法基本上是在重塑Map.get方法,如果找不到指定的密钥,则该方法将返回null。
Wyzard answered 2020-01-12T01:27:25Z
3 votes
对于Java 8,我建议在此用例中使用Optional。
Optional findUserByName(Collection users, String name){
Optional value = users
.stream()
.filter(a -> a.equals(name))
.findFirst();
}
这也使调用者很清楚,如果找不到该值,则可选参数可以为空。 如果您确实要引发异常,则可以在Optional中使用orElseThrows来实现它。
Alastor Moody answered 2020-01-12T01:27:50Z