正例:
try { String ip = "某ip"; int port = 8080; // 通过socket,连接网络中的某个节点 new Socket().connect(new InetSocketAddress(ip, port));} catch (Exception e) { // 一把梭,出错打印,爱咋咋滴 e.printStackTrace();}
反例:
String ip = "某ip";int port = 8080;try { // 通过socket,连接网络中的某个节点 new Socket().connect(new InetSocketAddress(ip, port));} catch (SocketException e) { //日志记录,同时输出非常堆栈 logger.log("网络连接非常 目标节点[ip={} port={}], 已连接或连接已关闭", ip, port, e); /陷入深奥深厚的思考中... 1.这个非常在当前语境下会造成什么影响 2.抛不抛出,不抛出我要做什么处理,如果抛出,除了记录日志,我还该当做些什么 3.虽然exception被我catch到了,但有没有可能遗漏其它非常 4.等等... /} catch (Exception e) { logger.log("发生了不可估量的网络连接非常 目标节点[ip={} port={}]", ip, port, e); /陷入深奥深厚的思考中 again... 重复以上思考过程... 在当前场景中,我认为网络连接非常本便是个checked exception,也便是说, 我要让调用我的人必须知道这点,由他决定怎么处理,兄弟对不住,我这把锅甩出去了 throw e; 又或者,根据业内最新思潮,万错皆可视为RuntimeException, 不过事没完,接下来我得在当前方法的throws子句中显式声明这些非常,好让别人知道... throw new RuntimeException(e);}//吾日三省吾身...//单元测试搞一搞?//覆盖度测试搞一搞?//代码有没有重复,是不是优雅,重构搞一搞?
2. JDK根本运行时非常,轻松捕获
Java开拓的基本类库JDK定义了一些开箱即用的运行时非常(RuntimeException),比如NullPointerException、IndexOutOfBoundsException等,这些非常不应该通过try-catch捕获来处理,而该当通过主动预检讨来处理,如下:

正例:
Biz biz = null;try { biz.run();} catch (NullPointerException e) { //轻松捕获臭名昭著的空指针非常,编程我最行!
}int[] arrays = new int[]{1, 2, 3};try {int a = arrays[4];} catch (IndexOutOfBoundsException e) { //轻松捕获臭名昭著的数组越界非常,编程我最行!
}
反例:
Biz biz = null;if (biz == null) { return;}biz.run();int[] array = new int[] {};if (array == null || array.length == 0) { return;}array[0] = 1;
3. 我也不知道哪会出错,try-catch罩起来,万无一失
catch时要分清,哪些代码不可能出错,哪些代码可能出错,不可能出错的不用try-catch(对新手来说,这点实在比较难做到),对付可能出错的代码进行try-catch,并尽可能针对非常分类处理,示例代码参考上文第1.条 ,此外,举两个栗子,如下:
包括且不限于 措辞层面的赋值语句、大略的getter/setter调用,根本不可能报错,不用try-catch某些第三方api/类库文档有时候会写某某方法抛出啥非常,你难道相信它永久按文档那样事情? 以是,建议try-catch(除非你是大牛钻进去识破代码,版本变革了你还得随着)最后记住,用try-catch包裹的代码是有性能开销的
4. 编译器总是报错,烦的一批,try-catch罩起来,天下安静了在Java中,对付checked非常,编译器会提示你进行try-catch,编译器那么谅解,你一定要好好处理啊,如下:
编译器报错高清无码图
发红了,赶紧try-catch起来,压压惊, 如下:
正例:
try { Thread.sleep(休眠毫秒数);} catch (InterruptedException e) { e.printStackTrace();}
反例:
try { Thread.sleep(休眠毫秒数);} catch (InterruptedException e) { logger.warn("线程{} 发生了中断", Thread.currentThread(), e); //通报中断旗子暗记(什么鬼?) Thread.currentThread().interrupt();}
5. 用非常来掌握程序流程,神乎其技
非常便是非常,它代表程序的意外情形,不要仗着try-catch能捕获非常,用这个机制来处理正常的程序流程,如下:
正例:
public static void check(String param) { if (param == null) throw new ParamExcetpion("参数为空!"); if (param.indexOf("敏感词") != -1) throw new SensitiveWordException("创造敏感词");}public static void handleParamError() { System.out.println("实行参数为空后的业务逻辑");}public static void handleSensitiveWord() { System.out.println("实行创造敏感词后的业务逻辑");}public static void main(String[] args) { String param = null; try { check(param); } catch (ParamExcetpion e) { handleParamError(); } catch (SensitiveWordException e) { handleSensitiveWord(); }}
反例:
String param = "未知值";if (param == null) { handleNull(); return;}if (param.indexOf("敏感词") != -1) { handleSensitiveWord();}
6.finally中别忘却资源工具的关闭和开释,我知道啊
finally块必须对资源型工具进行关闭,以防泄露,在这个过程中,针对某个特定资源工具的关闭,有任何非常都要做try-catch,防止close意外被miss掉,如下:
正例:
FileInputStream in = null;FileOutputStream out = null;try { in = new FileInputStream("in.txt"); out = new FileOutputStream("out.txt");} catch (Exception e) { e.printStackTrace();} finally { try { //妥妥关闭in和out in.close(); out.close(); } catch (IOException e) { e.printStackTrace(); }}
反例:
FileInputStream in = null;FileOutputStream out = null;try { in = new FileInputStream("in.txt"); out = new FileOutputStream("out.txt");} catch (Exception e) { // log略 throw new RuntimeException("文件读写缺点", e);} finally { if (in != null) { try { in.close(); } catch (Exception e) { // 主动吞咽非常 log略 } } if (out != null) { try { out.close(); } catch (Exception e) { // 主动吞咽非常 log略 } }}
7. try-finally终于形成肌肉影象了,不出牌了
Java SDK的版本不断升级,这门措辞始终在飞速发展,我们玩技能的也该当多多与时俱进,无论是新的语法糖还是内部实现(多表现为性能提升),都应多多关注,比如jdk7往后,支持try-with-resources语法糖,类只要实现了java.io.Closable接口,都可以沾恩,这种语法糖直接在措辞层面为你简化了 迂腐冗长的try-finally处理范式,来看:
正例:
FileInputStream in = null;try { in = new FileInputStream("in.txt");} catch (Exception e) { throw new RuntimeException("文件读写缺点", e);} finally { if (in != null) { try { in.close(); } catch (Exception e) { // 主动吞咽非常 log略 } }}
反例:
try (FileInputStream in = new FileInputStream("in.txt")) {} catch (Exception e) { // log略 throw new RuntimeException("文件读写缺点", e);}
8. 任何非常,只要能捕获住Exception兜底处理下,满满健壮感
在某些情形下,程序抛出的root非常并不一定都是Exception,要知道Java中还有一种非常的root叫做java.lang.Error,当潜在地,可能有Error抛出时,必须捕获Throwable。
正例:
static void weird1() throws NoSuchMethodError { throw new NoSuchMethodError("weird1");}static void weird2() throws Exception { weird2();}public static void main(String[] args) { try { weird1(); } catch (Exception e) { System.out.println("妥妥捉住weird1非常,妥妥滴!
"); } try { weird2(); } catch (Exception e) { System.out.println("妥妥捉住weird2非常,奥利给!
"); }}
反例:
try { weird1();} catch (Throwable e) { System.out.println("妥妥捉住weird1非常,妥妥滴!
9. 自定义非常,吃饱了撑的吧
");}try { weird2();} catch (Throwable e) { System.out.println("妥妥捉住weird2非常,奥利给!
");}
在适当的时候,或者说在业务变得越来越繁芜的时候,自定义非常这件事便是顺理成章的了,来看:
正例:
static void bizA() throws RuntimeException { throw new RuntimeException("sth error");}static void bizB() throws RuntimeException { throw new RuntimeException("sth error");}static void call() { bizA(); bizB();}public static void main(String[] args) { try { call(); } catch (Exception e) { //现在就把这个非常show给你看,当看到sth error时,你一定不会关心是bizA还是bizB的错,easy life! System.out.println(e); }}
反例:
static class ExceptionOfA extends RuntimeException { public ExceptionOfA(String message) { super(message); }}static class ExceptionOfB extends RuntimeException { public ExceptionOfB(String message) { super(message); }}static void bizA() throws ExceptionOfA { throw new ExceptionOfA("sth error");}static void bizB() throws ExceptionOfB { throw new ExceptionOfB("sth error");}static void call() { bizA(); bizB();}public static void main(String[] args) { try { call(); } catch (ExceptionOfA e) { //针对bizA的非常,我们用方案xxx来应对 } catch (ExceptionOfB e) { //针对bizB的非常,我们用方案yyy来应对 }}
10. DRY原则,别整那洋玩意儿
DRY原则,Don't Repeat Yourself,谢绝重复代码!
正例:
static class ExceptionOfA extends RuntimeException {}static class ExceptionOfB extends RuntimeException {}static void bizA() throws ExceptionOfA {}static void bizB() throws ExceptionOfB {}static void call() { bizA(); bizB();}//我是非常处理方案xxxstatic void handleError(Exception e) {}public static void main(String[] args) { try { call(); } catch (ExceptionOfA e) { //针对bizA的非常,我们用方案xxx来应对 handleError(e); } catch (ExceptionOfB e) { //针对bizB的非常,我们也用方案xxx来应对 handleError(e); }}
反例:
public static void main(String[] args) { try { call(); } catch (ExceptionOfA | ExceptionOfB e) { //针对bizA和bizB的非常,我们都用方案xxx来应对 handleError(e); }}
11. 非常没写文档,遗漏处理,怪我咯?
非常文档化,这样让调用者或者掩护者能够更清晰地知道你这个方法的约定、细节等等,这不仅仅表示在javadoc上,还表示在你的throws子句上(P.S. 这点不是逼迫的),当代的IDE还可以为有throws子句声明的非常自动天生try-catch处理的模版代码
正例:
static class AaException extends RuntimeException {}static class BbException extends RuntimeException {}static void biz(boolean a, boolean b) { if (a) throw new AaException(); if (b) throw new BbException();}public static void main(String[] args) { //程序员小明引入了某个jar包,biz方法是该jar包中某类的某方法 //小明扫了眼javadoc,没有任何关于参数和非常的描述,调用无忧!
biz(false, true);}
反例:
/ @throws AaException 这是一个xxx非常,发生它时,常日意味着你该当... @throws BbException 这是一个yyy非常,发生它时,常日意味着你该当... /static void biz(boolean a, boolean b) throws AaException, BbException { if (a) throw new AaException(); if (b) throw new BbException();}public static void main(String[] args) { // 程序员小明引入了某个jar包,biz方法是该jar包中某类的某方法 // 小明扫了眼javadoc,创造有关于非常的详细描述,他赶紧利用IDE的自动天生try/catch处理块功能,编写更为健壮的程序 try { biz(false, true); } catch (AaException e) { //处理略... } catch (BbException e) { //处理略... }}
12. 根因非常,这又是什么鬼
抛出非常的同时,应带上底层的非常堆栈,不要埋没根因(root cause,即追本溯源,根本缘故原由非常)
正例
static class ServiceException extends RuntimeException { public ServiceException(String message) { super(message); }}static class DbException extends RuntimeException { public DbException(String message) { super(message); }}static void service() throws ServiceException { try { dbOps(); } catch (Exception e) { throw new ServiceException("业务非常"); }}static void dbOps() throws DbException { throw new DbException("删库非常");}public static void main(String[] args) { try { service(); } catch (Exception e) { //业务非常而已,小场面!
e.printStackTrace(); }}
反例
static class ServiceException extends RuntimeException { public ServiceException(String message, Throwable cause) { super(message, cause); }}static class DbException extends RuntimeException { public DbException(String message) { super(message); } public DbException(String message, Throwable cause) { super(message, cause); }}static void service() throws ServiceException { try { dbOps(); } catch (Exception e) { //抛出非常的同时,带上底层的非常堆栈,不要埋没根因(root cause,根本缘故原由非常) throw new ServiceException("业务非常", e); }}static void dbOps() throws DbException { throw new DbException("删库非常");}public static void main(String[] args) { try { service(); } catch (Exception e) { //业务非常而已,小场面!
13. 喂,你这接口返回了个啥,你品你细品(TBD)14. 大俗大雅,说说null
等一等、删库了!
!
!
e.printStackTrace(); }}
编程履历越来越丰富的同学们,开始喜好在方法有返回值时,给个空的list、工具什么的了,而不是直接返回null,这样可以防止调用者调用你这个方法时,收到空指针非常,实在这倒不是逼迫的。本来调用者对null的处理便是他的任务所在,况且空工具、空list都是工具,有内存开销。还有便是,处理空list、空工具还有一些高等技巧,并不大略的。以是,脑细胞留给其它问题吧,骚年!
Spring的事务中,如果抛出了非常,那么事务是可以自动回滚的,但那有个条件,抛出的非常得是RuntimeException(或其子类)
正例
@Transactionalvoid service() { //1.往db里insert了条记录 //2.往db里update了条记录 //3.仿照抛出非常,表面有Spring的@Transactional老大哥罩着,之前对db的操作定能回滚,easy life! throw new Exception("调用失落败");}
反例
//此处必须显式声明,对Exception也须要按需回滚//(老大哥:我只能自动识别到RuntimeException,而对付Exception,你不说我怎么知道你想要?)@Transactional(rollbackFor=Exception.class)void service() { //1.往db里insert了条记录 //2.往db里update了条记录 //3.仿照抛出非常,表面有Spring的@Transactional老大哥罩着,之前对db的操作定能回滚,easy life! throw new Exception("调用失落败");}
本文部分参考了阿里巴巴Java开拓手册,融入了自己的一些解读和扩展,愿对你有所帮助
___________________________我是一条分割线之:第一重已成___________________________
神功未成,连续修炼...
历史文章:
管理类
软件行业从起步到转型,你所要理解的妙点
项目经理的升迁之道
技能类
Java非常处理葵花宝典(第一重)