在实际编程中,常常会遇到这样的情况,多个if语句嵌套使用,我曾见过最深的嵌套达4个,简直让人抓狂,通常代码可读性随着嵌套的层数增多而几何级数的降低。似我这等凡夫俗子,到4层几乎很难凭借肉眼看出代码的含义了。那么如何避免多if语句嵌套呢?看下面的例子。
在Spring MVC中,我们通常会定义我们的统一异常处理类,由它来捕获系统的异常。像下面这样
public class ExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {}
}
我们将在resolveException中写我们的异常处理逻辑
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if(ex instanceof NullPointerException){
//do something
}else if(ex instanceof IllegalArgumentException){
//do something
}else if(ex instanceof IllegalAccessException){
//do something
}
}
上面这段代码看起来还好,判断下异常的类型,然后做出不同的处理。那么再复杂一些的情况呢?如果抛出IllegalArgumentException,那么我们判断是哪个请求抛出的,并记录用户信息,根据用户的行为(正常用户,恶意攻击)告诉他是参数的完整格式还是直接拒绝。通常情况下,我们是会抽象出一个方法来做这件事。那么有没有别的方法呢?看下面的代码
private static Map<Class, ExceptionHandler> exceptionHandlerMap = Maps.newHashMap();
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ExceptionHandler exceptionHandler = exceptionHandlerMap.get(ex.getClass());
if (exceptionHandler == null) {
exceptionHandler = exceptionHandlerMap.get(DEFAULT_HANDLER);
}
LogUtil.ERROR_LOGGER.error("request {} parameter is {} error", request.getRequestURL(), JsonUtil.writeAsString(request.getParameterMap()));
exceptionHandler.handle(request, response, handler, ex);
return null;
}
interface ExceptionHandler {
void handle(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
上面的代码抽象出一个ExceptionHandler接口,用于处理异常。而exceptionHandlerMap则持有ExceptionHandler的引用。当异常发生时,根据异常类型,从exceptionHandlerMap中取出对应的处理方法。exceptionHandlerMap的初始化如下
private static final Class DEFAULT_HANDLER = null;
static {
//非法参数
exceptionHandlerMap.put(IllegalArgumentException.class, new ExceptionHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//do something
}
});
//非法访问
exceptionHandlerMap.put(IllegalAccessException.class, new ExceptionHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//do something
}
});
//null point exception
exceptionHandlerMap.put(NullPointerException.class, new ExceptionHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//do something
}
});
//exception
exceptionHandlerMap.put(Exception.class, new ExceptionHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//do something
}
});
//默认handler
exceptionHandlerMap.put(DEFAULT_HANDLER, new ExceptionHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//do something
}
});
}
故事到这里就结束了。当然,上面的case其实还有优化的空间,作为一个懒人,你让我写这么多的初始化语句干啥?最好是我实现一个ExceptionHandle你就给我自动注册到Map里就好了。那么怎么实现呢?我想到两种方式,1.spring自动注入; 2.enum。具体方法就不说了,推荐使用enum,不需要与spring集成,且java语言保证了单例。