Java中的异常(Exception)又称为例外,是一个在程序执行期间发生的事件,它中断正在执行程序的正常指令流。为了能够及时有效地处理程序中的运行错误,必须使用异常类。
<a href="#1printStackTrace_8">1、不要使用printStackTrace()</a> <a href="#2Exception_31">2、不要用一个Exception捕捉所有异常</a> <a href="#3catch_64">3、不要在catch块中吃掉异常</a> <a href="#4finallytrywithresource_86">4、使用finally或者try-with-resource,关闭流资源</a> <a href="#5_141">5、捕获异常与抛出异常必须是完全匹配,或者捕获异常是抛异常的父类</a> <a href="#6_169">6、捕获到的异常,不能忽略</a> <a href="#7_194">7、注意异常对你的代码层次结构的侵染(早发现早处理)</a> <a href="#8Throwable_cause_216">8、自定义封装异常,不要丢弃原始异常的信息Throwable cause</a> <a href="#9_RuntimeExceptioncatch__296">9、 先预检查运行时异常RuntimeException,不应该通过catch 的方式来处理</a> <a href="#10_313">10、优先捕获具体的异常</a>
<hr>
反例:
try {
int i =1/0;
} catch (Exception e) {
e.printStackTrace();
}
正例:
try {
int i =1/0;
} catch (Exception e) {
logger.error("异常信息:{}",e);
}
注意!!!
printStackTrace()打印出的堆栈日志跟业务代码日志是交错混合在一起的,通常排查异常日志不太方便。 e.printStackTrace()语句产生的字符串记录的是堆栈信息,如果信息太长太多,字符串常量池所在的内存块没有空间了,即内存满了,那么,用户的请求就被卡住。
反例:
public void test(){
try{
//…抛出 IOException 的代码调用
//…抛出 SQLException 的代码调用
}catch(Exception e){
//用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息哦
logger.error(“Exception in test,exception:{}”, e);
}
}
正例:
public void test(){
try{
//…抛出 IOException 的代码调用
//…抛出 SQLException 的代码调用
}catch(IOException e){
//仅仅捕捉 IOException
logger.error(“IOException in test,exception:{}”, e);
}catch(SQLException e){
//仅仅捕捉 SQLException
logger.error(“SQLException in test,exception:{}”, e);
}
}
注意!!!
用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息
反例:
try {
int i =1/0;
} catch (Exception e) {
logger.error("异常信息");
}
正例:
try {
int i =1/0;
} catch (Exception e) {
logger.error("异常信息:{}",e);
}
注意!!!
没有把exception打印出来,这样异常就会被吞掉,无法获取到任何失败信息,会给日后的问题排查带来巨大困难。
反例:
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(new File("/document.txt"));
fileInputStream.close();
} catch (FileNotFoundException e) {
logger.error(e);
} catch (IOException e) {
logger.error(e);
}
正例 1 使用finally关闭流资源:
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(new File("/document.txt"));
} catch (FileNotFoundException e) {
logger.error(e);
} catch (IOException e) {
logger.error(e);
}finally {
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
logger.error(e);
}
}
正例 2 使用try-with-resource来处理:
try (FileInputStream fis = new FileInputStream("D:\\小滴课堂\\a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("D:\\小滴课堂\\b.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
) {
int size;
byte[] buf = new byte[1024];
while ((size = bis.read(buf)) != -1) {
bos.write(buf, 0, size);
}
} catch (Exception e) {
logger.error(e);
}
// 在try()里面定义多个资源,执行完成后会自动关闭,关闭顺序是最先关闭最后在try()中定义的资源。
注意!!!
如果不使用finally或者try-with-resource,当程序发生异常,IO资源流没关闭,那么这个IO资源就会被他一直占着,这样别人就没有办法用了,这就造成资源浪费。
反例:
//BizException 是 Exception 的子类
public class BizException extends Exception {}
//抛出父类Exception
public static void test() throws Exception {}
try {
//编译错误
test();
//捕获异常子类是没法匹配
} catch (BizException e) {
log.error(e);
}
正例:
//抛出子类Exception
public static void test() throws BizException {}
try {
test();
} catch (Exception e) {
log.error(e);
}
反例:
public static void testIgnoreException() throws Exception {
try {
int i =1/0;
} catch (Exception e) {
}
}
正例 :
public static void testIgnoreException() throws Exception {
try {
int i =1/0;
} catch (Exception e) {
logger.error("异常信息:{}",e);
}
}
注意!!!
虽然一个正常情况都不会发生的异常,但是如果你捕获到它,就不要忽略。
反例:
public UserInfo queryUserInfoByUserId(Long userid) throw SQLException {
//根据用户Id查询数据库
}
正例 :
public UserInfo queryUserInfoByUserId(Long userid) {
try{
//根据用户Id查询数据库
}catch(SQLException e){
log.error("查询数据库异常啦,{}",e);
}finally{
//关闭连接,清理资源
}
}
反例:
public class TestChainException {
public void readFile() throws MyException{
try {
InputStream is = new FileInputStream("jay.txt");
Scanner in = new Scanner(is);
while (in.hasNext()) {
System.out.println(in.next());
}
} catch (FileNotFoundException e) {
//e 保存异常信息
throw new MyException("文件在哪里呢");
}
}
public void invokeReadFile() throws MyException{
try {
readFile();
} catch (MyException e) {
//e 保存异常信息
throw new MyException("文件找不到");
}
}
public static void main(String[] args) {
TestChainException t = new TestChainException();
try {
t.invokeReadFile();
} catch (MyException e) {
e.printStackTrace();
}
}
}
//MyException 构造器
public MyException(String message) {
super(message);
}
正例 :
public class TestChainException {
public void readFile() throws MyException{
try {
InputStream is = new FileInputStream("jay.txt");
Scanner in = new Scanner(is);
while (in.hasNext()) {
System.out.println(in.next());
}
} catch (FileNotFoundException e) {
//e 保存异常信息
throw new MyException("文件在哪里呢", e);
}
}
public void invokeReadFile() throws MyException{
try {
readFile();
} catch (MyException e) {
//e 保存异常信息
throw new MyException("文件找不到", e);
}
}
public static void main(String[] args) {
TestChainException t = new TestChainException();
try {
t.invokeReadFile();
} catch (MyException e) {
e.printStackTrace();
}
}
}
//MyException 构造器
public MyException(String message, Throwable cause) {
super(message, cause);
}
反例:
try {
obj.method()
} catch (NullPointerException e) {
...
}
正例 :
if (obj != null){
...
}
注意异常的匹配顺序,因为只有第一个匹配到异常的catch块才会被执行。如果你希望看到,是NumberFormatException异常,就抛出NumberFormatException,如果是IllegalArgumentException就抛出IllegalArgumentException。 反例:
try {
doSomething("test exception");
} catch (IllegalArgumentException e) {
log.error(e);
} catch (NumberFormatException e) {
log.error(e);
}
正例 :
try {
doSomething("test exception");
} catch (NumberFormatException e) {
log.error(e);
} catch (IllegalArgumentException e) {
log.error(e);
}
注意!!!
因为NumberFormatException是IllegalArgumentException 的子类,反例中,不管是哪个异常,都会匹配到IllegalArgumentException,就不会再往下执行啦,因此不知道是否是NumberFormatException。所以需要优先捕获具体的异常,把NumberFormatException放前面。
本站为非盈利网站,如果您喜欢这篇文章,欢迎支持我们继续运营!
本站主要用于日常笔记的记录和生活日志。本站不保证所有内容信息可靠!(大多数文章属于搬运!)如有版权问题,请联系我立即删除:“abcdsjx@126.com”。
QQ: 1164453243
邮箱: abcdsjx@126.com