2016-08-23 61 views
-1

当一个子方法抛出一个异常时,封装在专用的“包”异常中会被认为是不错的实践吗?通过组件抛出异常,良好实践?

public String doStuff() throws UtilsException { 
     try { 
      throw new NullPointerException("test"); 
     } catch (NullPointerException e) { 
      throw new UtilsException("something occured", e); 
     } 
    } 

    //use this exception for all classes of this package/component 
    public class UtilsException extends Exception { 
     private static final long serialVersionUID = 1L; 

     public UtilsException() { 
      super(); 
     } 

     public UtilsException(String message, Throwable cause) { 
      super(message, cause); 
     } 

     public UtilsException(String message) { 
      super(message); 
     } 

     public UtilsException(Throwable cause) { 
      super(cause); 
     } 

    } 

可能Optional.empty()是避免抛/复杂的应用程序的捕捉的方法吗?

public Optional<String> doStuff() throws UtilsException { 
     try { 
      return Optional.of("ok"); 
     } catch (NullPointerException e) { 
      LOG.error("Something append... {}", e.getMessage()); 
      return Optional.empty(); 
     } 
    } 
+1

在某些设置中将低级异常包装为高级异常可能是一种很好的做法,但是如果您正在讨论'NullPointerException',则不是。你甚至不应该捕获一个'NullPointerException'。它在你的所有应用程序中具有相同的含义。一个'Optional'封装了一个可能缺少的值,而不是一个发生'NullPointerException'的报告。首先避免'NullPointerException'。你可以通过使用'Optional'来做到这一点。 – Holger

+0

NullPointerException只是为了解释我的设置。遵循异常的来源,包装看起来很有趣。 –

+1

然后你选择了一个非常糟糕的例子。考虑一下,一个'ClassNotFoundException'封装了加载类字节时发生的IOException。特殊情况是API层不允许检查异常,例如考虑数据库的“集合”视图。在那里,底层存储系统的故障必须被打包,例如,在'IllegalStateException's或'NoSuchElementException's中。我认为,这些都是更好的例子。 – Holger

回答

1

首先,你应该永远一个NullPointerException(或运行时异常一般)的回报成才别的喜欢你正在做的。 好吧,也许有一些情况下,你需要这样做(像一个越野车第三方api)。

当你的程序有一个错误,你应该让它们冒泡并在你的程序的一些高阶组件中处理它们时,会发生类似于那些(NullPointer,ClassCast,IllegalArgument等)的异常。

话虽这么说,(有来自臭名昭著的短语),这取决于...

例外是错误的通知“负责”,因此他们需要信息的调用者将使用它们来什么决定做。考虑以下几点:

public void readFile(String path) throws IOException { 
    // read file content 
    return content; 
} 


try { 
    return readFile("foo.txt"); 
} catch(FileNotFound e) { 
    // For this specific scenario not finding the file is not a problem  
    return ""; 
} catch(IOException e) { 
    // This we are not expecting to happen, if the file exists we should be 
    // able to read it, otherwise we should inform the user. 
    log.error(e); 
    display("We had a problem reading the file, Check the file permissions and try again"); 
} 

正如你可以在上面的例子中看到的,你不会想换IOException异常的另一个异常在这种情况下 因为你会删除客户端来决定做什么时能力发生错误。

另外,还要注意IOException异常是“包装”,因为异常的对象也可以使用继承 来概括你的方法将引发什么样的错误,然后抛出更具体的错误,以便调用者可以 决定形式是什么去做。

何时换行。

有些情况下,包装异常是一个很好的做法,是要走的路。 例如,如果您创建的主要功能是获取天气信息的库。

对于第一个版本,您保持简单并使用第三方api来获取当天的值。 你的API的主要方法是这样的。

public Weather getWeather(Date day) throws HTTPException { 
    return weather.get(day); 
} 

您的API是做得相当不错,但你是否注意到你正在做太多的请求天气API和 你将不得不很快开始为它付出代价。然后您决定将结果缓存在数据库表 中,以便减少请求数量。

public Weather getWeather(Date day) throws HTTPException, SQLException { 
    Weather w = getFromCache(day); 
    if (w != null) { 
     return w; 
    } else { 
     return getAndCache(day); 
    } 
} 

现在你有一个问题,在抛出的语句,因为你肯定会打破你的 API的用户代码,你可以不加这个新的异常。

如果你仔细想想,如果你的缓存中存在从api或 获取数据时出现问题,那么你的api用户不会感兴趣,他们只是想知道错误。这是一个很好的例子,将 中的例外列入更通用的例外,如WeatherFetchException

正如你所看到的,它实际上取决于...

我的经验法则是,保持你的例外有意义,如果你想包装他们,只是做的时候 这是有道理的以及何时不删除调用者处理错误的能力。

仅仅为了它而包装异常绝对不是一个好习惯。