通过组件抛出异常,良好实践?

时间:2016-08-23 12:38:48

标签: java java-8

当sub方法抛出异常时,将封装在专用的"包中。异常被视为良好的实践?

    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 个答案:

答案 0 :(得分:1)

首先,你应该从不捕获NullPointerException(或者一般的运行时异常)和其他类似的返回。 好吧,也许很少有你需要这样做的情况(比如有缺陷的第三方api)。

当您的程序出现错误并且您应该让它们出现异常时(例如NullPointer,ClassCast,IllegalArgument等) 它们冒泡并在程序的某个高阶组件中处理它们。

话虽如此,(并且有臭名昭着的短语)取决于......

例外是&#34;负责任&#34;为了通知错误,因此他们需要提供信息,呼叫者将使用它们来决定做什么。请考虑以下事项:

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是&#34; wrap&#34;的一种形式。因为异常也是对象,所以你可以使用继承 概括你的方法抛出什么样的错误,然后抛出更多特定的错误,以便调用者可以 决定做什么。

何时换行。

有些情况下,包装异常是一种很好的做法,并且是可行的方法。 例如,如果您要创建一个lib,其主要功能是获取天气信息。

对于第一个版本,您保持简单并使用第三方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);
    }
}

现在你遇到了问题,你不能将这个新的异常添加到throws语句中,因为你肯定会破坏 你api的用户代码。

如果您考虑一下,如果您从wheter api获取数据时遇到问题,那么您的api用户就不感兴趣了 从您的缓存中,他们只是想知道错误。这是将这些异常包装起来的一个非常好的案例 一个更通用的,如WeatherFetchException

正如您所看到的,这实际上取决于......

我的经验法则是,保持您的例外意义,如果您想要包装它们,请仅在 这是有道理的,什么时候它不会消除来电者处理错误的能力。

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