重庆seo整站优化设置网页游戏破解版
news/
2025/9/25 16:11:57/
文章来源:
重庆seo整站优化设置,网页游戏破解版,大型网站技术方案,建设门户网站发展前景2018前言
在我们日常工作中#xff0c;经常会遇到一些异常#xff0c;比如#xff1a;NullPointerException、NumberFormatException、ClassCastException等等。
那么问题来了#xff0c;我们该如何处理异常#xff0c;让代码变得更优雅呢#xff1f; 1 不要忽略异常
不知…前言
在我们日常工作中经常会遇到一些异常比如NullPointerException、NumberFormatException、ClassCastException等等。
那么问题来了我们该如何处理异常让代码变得更优雅呢 1 不要忽略异常
不知道你有没有遇到过下面这段代码
反例
Long id null;
try {id Long.parseLong(keyword);
} catch(NumberFormatException e) {//忽略异常
}用户输入的参数使用Long.parseLong方法转换成Long类型的过程中如果出现了异常则使用try/catch直接忽略了异常。并且也没有打印任何日志。如果后面线上代码出现了问题有点不太好排查问题。建议大家不要忽略异常在后续的工作中可能会带来很多麻烦。
正例
Long id null;
try {id Long.parseLong(keyword);
} catch(NumberFormatException e) {log.info(String.format(keyword{} 转换成Long类型失败原因{},keyword , e))
}后面如果数据转换出现问题从日志中我们一眼就可以查到具体原因了。
2 使用全局异常处理器
有些经常喜欢在Service代码中捕获异常。不管是普通异常Exception还是运行时异常RuntimeException都使用try/catch把它们捕获。
反例
try {checkParam(param);
} catch (BusinessException e) {return ApiResultUtil.error(1,参数错误);
}在每个Controller类中都捕获异常。在UserController、MenuController、RoleController、JobController等等都有上面的这段代码。显然这种做法会造成大量重复的代码。我们在Controller、Service等业务代码中尽可能少捕获异常。这种业务异常处理应该交给拦截器统一处理。在SpringBoot中可以使用RestControllerAdvice注解定义一个全局的异常处理handler然后使用ExceptionHandler注解在方法上处理异常。
例如
Slf4j
RestControllerAdvice
public class GlobalExceptionHandler {/*** 统一处理异常** param e 异常* return API请求响应实体*/ExceptionHandler(Exception.class)public ApiResult handleException(Exception e) {if (e instanceof BusinessException) {BusinessException businessException (BusinessException) e;log.info(请求出现业务异常, e);return ApiResultUtil.error(businessException.getCode(), businessException.getMessage());} log.error(请求出现系统异常, e);return ApiResultUtil.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), 服务器内部错误请联系系统管理员);}}有了这个全局的异常处理器之前我们在Controller或者Service中的try/catch代码可以去掉。
如果在接口中出现异常全局的异常处理器会帮我们封装结果返回给用户。
3 尽可能捕获具体异常
在你的业务逻辑方法中有可能需要去处理多种不同的异常。你可能你会觉得比较麻烦而直接捕获Exception。
反例
try {doSomething();
} catch(Exception e) {log.error(doSomething处理失败原因,e);
}这样捕获异常太笼统了。其实doSomething方法中会抛出FileNotFoundException和IOException。这种情况我们最好捕获具体的异常然后分别做处理。
正例
try {doSomething();
} catch(FileNotFoundException e) {log.error(doSomething处理失败文件找不到原因,e);
} catch(IOException e) {log.error(doSomething处理失败IO出现了异常原因,e);
}这样如果后面出现了上面的异常我们就非常方便知道是什么原因了。
4 在finally中关闭IO流
我们在使用IO流的时候用完了之后一般需要及时关闭否则会浪费系统资源。我们需要在try/catch中处理IO流因为可能会出现IO异常。
反例
try {File file new File(/tmp/1.txt);FileInputStream fis new FileInputStream(file);byte[] data new byte[(int) file.length()];fis.read(data);for (byte b : data) {System.out.println(b);}fis.close();
} catch (IOException e) {log.error(读取文件失败原因,e)
}上面的代码直接在try的代码块中关闭fis。假如在调用fis.read方法时出现了IO异常则可能会直接抛异常进入catch代码块中而此时fis.close方法没办法执行也就是说这种情况下无法正确关闭IO流。
正例
FileInputStream fis null;
try {File file new File(/tmp/1.txt);fis new FileInputStream(file);byte[] data new byte[(int) file.length()];fis.read(data);for (byte b : data) {System.out.println(b);}
} catch (IOException e) {log.error(读取文件失败原因,e)
} finally {if(fis ! null) {try {fis.close();fis null;} catch (IOException e) {log.error(读取文件后关闭IO流失败原因,e)}}
}在finally代码块中关闭IO流。但要先判断fis不为空否则在执行fis.close()方法时可能会出现NullPointerException异常。需要注意的地方时在调用fis.close()方法时也可能会抛异常我们还需要进行try/catch处理。
5 多用try-catch-resource
前面在finally代码块中关闭IO流还是觉得有点麻烦。因此在JDK7之后出现了一种新的语法糖try-with-resource。上面的代码可以改造成这样的
File file new File(/tmp/1.txt);
try (FileInputStream fis new FileInputStream(file)) {byte[] data new byte[(int) file.length()];fis.read(data);for (byte b : data) {System.out.println(b);}
} catch (IOException e) {e.printStackTrace();log.error(读取文件失败原因,e)
}try括号里头的FileInputStream实现了一个AutoCloseable接口所以无论这段代码是正常执行完还是有异常往外抛还是内部代码块发生异常被截获最终都会自动关闭IO流。我们尽量多用try-catch-resource的语法关闭IO流可以少写一些finally中的代码。而且在finally代码块中关闭IO流有顺序的问题如果有多种IO关闭的顺序不对可能会导致部分IO关闭失败。而try-catch-resource就没有这个问题。
6 不在finally中return
我们在某个方法中可能会有返回数据。
反例
public int divide(int dividend, int divisor) {try {return dividend / divisor;} catch (ArithmeticException e) {// 异常处理} finally {return -1;}
}上面的这个例子中我们在finally代码块中返回了数据-1。这样最后在divide方法返回时会将dividend / divisor的值覆盖成-1导致正常的结果也不对。我们尽量不要在finally代码块中返回数据。
正解
public int divide(int dividend, int divisor) {try {return dividend / divisor;} catch (ArithmeticException e) {// 异常处理return -1;}
}如果dividend / divisor出现了异常则在catch代码块中返回-1。
7 少用e.printStackTrace()
我们在本地开发中喜欢使用e.printStackTrace()方法将异常的堆栈跟踪信息输出到标准错误流中。
反例
try {doSomething();
} catch(IOException e) {e.printStackTrace();
}这种方式在本地确实容易定位问题。但如果代码部署到了生产环境可能会带来下面的问题 可能会暴露敏感信息如文件路径、用户名、密码等。 可能会影响程序的性能和稳定性。
正解
try {doSomething();
} catch(IOException e) {log.error(doSomething处理失败原因,e);
}我们要将异常信息记录到日志中而不是保留给用户。
8 异常打印详细一点
我们在捕获了异常之后需要把异常的相关信息记录到日志当中。
反例
try {double b 1/0;
} catch(ArithmeticException e) {log.error(处理失败原因,e.getMessage());
}这个例子中使用e.getMessage()方法返回异常信息。但执行结果为
doSomething处理失败原因这种情况异常信息根本没有打印出来。我们应该把异常信息和堆栈都打印出来。
正例
try {double b 1/0;
} catch(ArithmeticException e) {log.error(处理失败原因,e);
}执行结果
doSomething处理失败原因
java.lang.ArithmeticException: / by zeroat cn.net.susan.service.Test.main(Test.java:16)将具体的异常出现问题的代码和具体行数都打印出来。
9 别捕获了异常又马上抛出
有时候我们为了记录日志可能会对异常进行捕获然后又抛出。
反例
try {doSomething();
} catch(ArithmeticException e) {log.error(doSomething处理失败原因,e)throw e;
}在调用doSomething方法时如果出现了ArithmeticException异常则先使用catch捕获记录到日志中然后使用throw关键抛出这个异常。这个骚操作纯属是为了记录日志。但最后发现日志记录两次。因为在后续的处理中可能会将这个ArithmeticException异常又记录一次。这样就会导致日志重复记录了。
10 优先使用标准异常
在Java中已经定义了许多比较常用的标准异常比如下面这张图中列出的这些异常 反例
public void checkValue(int value) {if (value 0) {throw new MyIllegalArgumentException(值不能为负);}
}自定义了一个异常表示参数错误。其实我们可以直接复用已有的标准异常。
正例
public void checkValue(int value) {if (value 0) {throw new IllegalArgumentException(值不能为负);}
}
11 对异常进行文档说明
我们在写代码的过程中有一个好习惯是给方法、参数和返回值增加文档说明。
反例
/* * 处理用户数据* param value 用户输入参数* return 值 */
public int doSomething(String value) throws BusinessException {//业务逻辑return 1;
}这个doSomething方法把方法、参数、返回值都加了文档说明但异常没有加。
正解
/* * 处理用户数据* param value 用户输入参数* return 值* throws BusinessException 业务异常*/
public int doSomething(String value) throws BusinessException {//业务逻辑return 1;
}抛出的异常也需要增加文档说明。
12 别用异常控制程序的流程
我们有时候在程序中使用异常来控制了程序的流程这种做法其实是不对的。
反例
Long id null;
try {id Long.parseLong(idStr);
} catch(NumberFormatException e) {id 1001;
}如果用户输入的idStr是Long类型则将它转换成Long然后赋值给id否则id给默认值1001。每次都需要try/catch还是比较影响系统性能的。
正例
Long id checkValueType(idStr) ? Long.parseLong(idStr) : 1001;我们增加了一个checkValueType方法判断idStr的值如果是Long类型则直接转换成Long否则给默认值1001。
13 自定义异常
如果标准异常无法满足我们的业务需求我们可以自定义异常。
例如
/*** 业务异常** author rice* date 2024/11/5*/
AllArgsConstructor
Data
public class BusinessException extends RuntimeException {public static final long serialVersionUID -6735897190745766939L;/*** 异常码*/private int code;/*** 具体异常信息*/private String message;public BusinessException() {super();}public BusinessException(String message) {this.code HttpStatus.INTERNAL_SERVER_ERROR.value();this.message message;}
}对于这种自定义的业务异常我们可以增加code和message这两个字段code表示异常码而message表示具体的异常信息。BusinessException继承了RuntimeException运行时异常后面处理起来更加灵活。提供了多种构造方法。定义了一个序列化IDserialVersionUID。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/917200.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!