Java异常处理:给程序罩一层保险
本着负责任的态度,我们程序员在写代码的时候,都非常的严谨。但程序在运行的时候,往往会出现一些令人意想不到的错误,导致那些不被期望的事件发生,最终,程序没有按照我们的预期正常地执行下去——异常发生了,是任程序自生自灭,还是将错误输出给用户?
Java为此提供的解决方案是——异常处理机制。
异常处理机制能够让程序在异常发生时,按照代码预先设定的异常处理规则,针对性地处理异常——要么恢复到程序一开始的样子,要么停止运行把详细的错误信息抛出来,让我们程序员知道哪里出了错,然后做出对应的优化。
人这一生,总会遇到一些不可预料的麻烦,这些麻烦可能会让我们遭受沉重的打击。为了减轻因此承受的负担,我们就会买保险。
异常处理机制在一定程度上保证了程序的健壮性,就好像给程序罩了一层保险。
01、 异常的分类
在Java中,异常被称为Throwable,可分为Error和Exception(英文直译为例外,但通常被称为真的‘异常’)。
Error:代表了Java虚拟机(Java Virtual Machine)本身的错误,不能通过代码进行处理。我们程序员最熟悉的Error就是OutOfMemoryError,该错误的原因是由于程序不严谨,产生了过多的垃圾,导致Java虚拟机内存溢出。
Exception:代表了程序运行时出现的各种例外(不被期望发生的事件),可分为检查(checked)异常和非检查(unchecked)异常。
编译器强制要求程序员为检查异常做预处理工作——捕获异常并处理或者抛出异常,否则编译器就会提示错误。常见的这类异常有SQLException
、IOException
和ClassNotFoundException
。
编译器不会提示非检查异常,也不要求在程序中处理这些异常。但通常情况下,程序员应该对这些异常有所防范 。比如说在进行除法运算的时候要对除数进行检查,保证其不能为0,否则程序在运行时就会抛出ArithmeticException
,如果这样的异常发生了,那只能说明编写这段代码的程序员很粗心。
可查看下图了解Java异常的分类:
02、 异常发生了
来看程序清单3-1:
package com.cmower.java_demo.twelve;
public class Cmower {
public static void main(String[] args) {
System.out.println(2 / 0);
System.out.println("程序已终止执行");
}
}
/*****************************************
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.cmower.java_demo.twelve.Cmower.main(Cmower.java:6)
*****************************************/
当除数为0时,将抛出ArithmeticException异常,程序不再继续执行——异常信息打印得非常详细,我们可以找到哪一行出了错,并且知道错误是由于除数为0引发的;假如不知道错误怎么解决,可以把第一行的错误信息复制粘贴进行搜索,有不少答案正是你需要的。
03 异常处理
程序清单3-1没有使用异常处理机制,也可以顺利编译,因为ArithmeticException异常是非检查异常。那如果遇到检查异常呢?
编译器会提醒异常未处理,见下图:
具体的代码如下:
public class Cmower {
public static void main(String[] args) {
FileInputStream fileIn = new FileInputStream("cmower.jpg");
}
}
那该如何处理异常呢?
如果是非检查异常,就需要在编码阶段对可能发生的错误进行规避,比如说,检查除数是否为0,如果为0就不要再做除法运算了。
如果是检查异常,做法大致有两种。
1)直接抛出错误
大学快毕业的时候,我感觉很迷茫,不知道未来要做什么,于是就打电话向父母求助,他们就劝我去一家软件培训园接受培训——自己决定不了的,就向上级请示。
这种现实的场景在Java中竟然也能找到相似之处。当一个方法不知道该怎么处理异常时,就可以使用throws
关键字将编译器提醒的错误抛出,抛出的错误直接交给方法调用者来处理。示例如下:
public class Cmower {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fileIn = new FileInputStream("cmower.jpg");
}
}
2)捕获错误
在软件培训园接受了两个月的培训后,我就被江苏富士通录用了,然后一干就是三年半。这三年多时间,我成长了很多,技术得到了很大的锻炼,于是就在五年前回到了洛阳——这一次,我没再向父母请示,因为我翅膀硬了,可以自己做决定了。
这种现实的场景在Java中仍然能找到相似之处。当一个方法知道自己该怎么处理异常时,就可以使用try
块将编译器提醒出错的代码段进行捕获,然后在catch
块中做出对应的处理。示例如下:
public class Cmower {
public static void main(String[] args) {
try {
FileInputStream fileIn = new FileInputStream("cmower.jpg");
} catch (FileNotFoundException e) {
System.err.println("读取的文件未找到:" + e.getMessage());
}
}
}
在我初学Java的时候,总喜欢直接捕获通用异常Exception
,而不是特定的异常(比如FileNotFoundException
),因为这样做很省事,除了少写几个字母之外,还不必担心其他异常出现时再另外捕获。
但这样做是有问题的。因为在日常的开发中,我们希望代码能够直观地体现出尽量多的信息,但不具体的Exception
会隐藏掉那些应该呈现出来的信息。
04、 异常处理的实战
1)表单验证
当我们需要在服务器端对用户输入的内容进行检查时,就可以利用异常处理机制。怎么做呢?
第一步,自定义异常类,继承RuntimeException(那些不受检查的异常类都继承自该类)。
public class OrderException extends RuntimeException {
public OrderException() {
super();
}
public OrderException(String message) {
super(message);
}
}
第二步,表单验证的时候,遇到不符合要求的用户输入时使用throw
关键字抛出自定义异常。
public static void check(String input) {
if (input == null) {
throw new OrderException("输入值不能为空");
}
if (input.length() < 10) {
throw new OrderException("字符串长度不能少于10个");
}
}
第三步,对自定义异常捕获,做出对应处理。
public class Cmower {
public static void main(String[] args) {
try {
check(args[0]);
} catch (OrderException e) {
System.err.println("用户输入条件有误:" + e.getMessage());
}
}
}
为什么要使用自定义异常来处理用户输入呢?因为用户输入需要检查很多项,而异常处理机制会在遇到第一项错误的时候就停下来,后面的代码是不会执行的——很贴合表单验证的场景。
2)使用日志记录异常的堆栈信息
在之前的例子当中,我们一直把错误信息打印在控制台,但正式的应用当中,日志是要被记录在日志文件中的,因为控制台记录的信息是有限的。
限于篇幅原因,日志相关的组件log4j、slf4j以及他们在项目中的配置请查阅资料。
当配置好日志组件后,就可以在需要记录日志信息的类中创建Logger,然后在catch块中使用logger.error(e.getMessage(), e);
记录详细的异常堆栈信息。具体示例如下:
package com.cmower.java_demo.twelve;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Cmower {
protected static Logger logger = LoggerFactory.getLogger(Cmower.class);
public static void check(String input) {
if (input == null) {
throw new OrderException("输入值不能为空");
}
if (input.length() < 10) {
throw new OrderException("字符串长度不能少于10个");
}
}
public static void main(String[] args) {
try {
check(null);
} catch (OrderException e) {
logger.error(e.getMessage(), e);
}
}
}
/*****************************************
ERROR 2019-01-08 21:38:35,696 com.cmower.java_demo.twelve.Cmower: 输入值不能为空
com.cmower.java_demo.twelve.OrderException: 输入值不能为空
at com.cmower.java_demo.twelve.Cmower.check(Cmower.java:10)
at com.cmower.java_demo.twelve.Cmower.main(Cmower.java:20)
*****************************************/
05、 finally
对于一些代码,我们希望无论try
块中的异常是否抛出,它们都能够得到执行,这就需要用到finally
——不管异常是否发生,只要对应的try
执行了,则它一定也执行。
finally块通常用来做资源释放操作:关闭文件、关闭socket连接、关闭数据库连接等等。示例如下:
try {
Socket socket = new Socket(serverIp, serverPort);
} catch (IOException e) {
logger.error(e.getMessage(), e);
} finally {
socket.close();
}
微信搜索「沉默王二」公众号,关注后回复「免费视频」获取 500G 高质量教学视频(已分门别类)。
Java异常处理:给程序罩一层保险的更多相关文章
- Day12 Java异常处理与程序调试
什么是异常? 不正常的,会影响程序的正常执行流程. 例如下面的程序 public static void main(String[] args) { TestDemo1 t = new TestDem ...
- Java异常处理:如何写出“正确”但被编译器认为有语法错误的程序
文章的标题看似自相矛盾,然而我在"正确"二字上打了引号.我们来看一个例子,关于Java异常处理(Exception Handling)的一些知识点. 看下面这段程序.方法pleas ...
- java异常处理的设计
有一句这样话:一个衡量Java设计师水平和开发团队纪律性的好方法就是读读他们应用程序里的异常处理代码. 本文主要讨论开发Java程序时,如何设计异常处理的代码,如何时抛异常,捕获到了怎么处理,而不是讲 ...
- Java异常处理机制难点解惑-用代码说话
是否需要看这篇文章? 下面的例子中,如果正常执行返回值多少? 如果出现了ArithmeticException返回值多少? 如果出现非ArithmeticException(如NullPointerE ...
- Java异常处理机制的秘密
一.结论 这些结论你可能从未听说过,但其正确性是毋庸置疑的,不妨先看看: 1.catch中throw不一定能抛回到上一层,因为finally中的return会抑制这个throw 2.finally中t ...
- 谈谈Java异常处理这件事儿
此文已由作者谢蕾授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 前言 我们对于"异常处理"这个词并不陌生,众多框架和库在异常处理方面都提供了便利,但是对于 ...
- Java异常处理的基础知识
Java中的异常捕获语句 Try{ //可能发生运行错误的代码: } catch(异常类型 异常对象引用){ //用于处理异常的代码 } finally{ //用于“善后” 的代码 } Java 中所 ...
- 札记:Java异常处理
异常概述 程序在运行中总会面临一些"意外"情况,良好的代码需要对它们进行预防和处理.大致来说,这些意外情况分三类: 交互输入 用户以非预期的方式使用程序,比如非法输入,不正当的操作 ...
- Java 异常处理
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error:如果你用System.out ...
随机推荐
- pwn学习之三
whctf2017的一道pwn题sandbox,这道题提供了两个可执行文件加一个libc,两个可执行文件是一个vuln,一个sandbox,这是一道通过沙盒去保护vuln不被攻击的题目. 用ida打开 ...
- Saltstack 集中化管理平台安装
Saltstack的简介 SaltStack(http://www.saltstack.com/)是一个服务器基础架构集中化管理平台,具备配置管理.远程执行.监控等功能,一般可以理解为简化版的pupp ...
- SVM原理 (转载)
1. 线性分类SVM面临的问题 有时候本来数据的确是可分的,也就是说可以用 线性分类SVM的学习方法来求解,但是却因为混入了异常点,导致不能线性可分,比如下图,本来数据是可以按下面的实线来做超平面分离 ...
- 在vue-cli3中优雅的使用 icon
首先我们得有图标 这里我们从网上下载svg文件或者UI给你导出svg文件 我们在src 文件下新建一个放置svg 文件 的文件夹 @/src/icons.将所有 icon 放在这个文件夹下. 创建 i ...
- vue 调用摄像头拍照以及获取相片本地路径(实测有效)
在学习这个的时候有一点前提:这是针对手机功能的,所以最重要的是要用手机进行实时调试 包含图片的增加和删除功能 <template> <div> <!--照片区域--> ...
- 多人合作项目如何去管理git仓库
前记:在git之前依稀记得有SVN去管理代码仓库,现在多用git去管理我们的代码:现在一般的项目大多数是多人同时开发,这样就会存在一个问题就是如何去协调开发:这也是lz当前使用git开发管理的些许经验 ...
- Handler Timer TimerTask ScheduledExecutor 循环任务解析
使用Handler执行循环任务 private Handler handler = new Handler(); private int mDelayTime = 1000; private Runn ...
- BZOJ5316 : [Jsoi2018]绝地反击
若$R=0$,那么显然答案为离原点最远的点到原点的距离. 否则若所有点都在原点,那么显然答案为$R$. 否则考虑二分答案$mid$,检查$mid$是否可行. 那么每个点根据对应圆交,可以覆盖圆上的一部 ...
- Hive管理表分区的创建,数据导入,分区的删除操作
Hive分区和传统数据库的分区的异同: 分区技术是处理大型数据集经常用到的方法.在Oracle中,分区表中的每个分区是一个独立的segment段对象,有多少个分区,就存在多少个相应的数据库对象.而在P ...
- js实现八皇后,回溯法
八皇后问题:将八个皇后摆在一张8*8的国际象棋棋盘上,使每个皇后都无法吃掉别的皇后,一共有多少种摆法? 两个皇后不能同时在同一行,同一列,和斜对角线的位置上,使用回溯法解决. 从第一行选个位置开始放棋 ...