异常处理是Java语言的相当大的优势,且很简单。
异常指的是导致程序中断执行的一种指令流。一旦发生异常且没有正常处理的话,程序将中断执行。
【举例】:观察产生异常的代码
System.out.println("AAAA");
System.out.println("计算="+(10/0));
System.out.println("BBBB");
以上代码发生异常,程序没有执行完毕,打印完AAAA后直接崩溃退出,这种情况是不能容忍的。
可以使用try、catch、finally三个关键字组合,完成正在执行的异常处理,语法如下,catch可以写多个:
try {
//有可能出现异常的语句
}catch (异常类型 对象){
//异常处理
}catch (异常类型 对象){
//异常处理
}finally {
//异常的统一出口代码
}
以上语法,也有三种组合模式:try...catch、try...catch...finally、try...finally
【举例】:利用try...catch 实现异常的处理操作
System.out.println("AAAA");
try {
int result = 10/0;
System.out.println("计算="+result);
}catch (ArithmeticException e){
System.out.println(e);
}
System.out.println("BBBB");
以上,我们发现程序可以正常运行,不会造成崩溃,但是代码还是有些问题,打印出的异常信息不完整,没发定位到具体是哪一行代码出了问题,可以用异常对象e的 printStackTrace()方法进行信息打印。
【举例】:利用try...catch...finally 结构进行异常处理
System.out.println("AAAA");
try {
int result = 10/0;
System.out.println("计算="+result);
}catch (ArithmeticException e){
e.printStackTrace();
}finally {
System.out.println("=========");
}
System.out.println("BBBB");
以上,我们发现,异常产生之后执行catch语句内容,而后处理异常完毕后继续执行finally代码。若没有产生异常呢?finally中的代码还会执行吗?答案是的,把10/0改为10/1观察打印结果:
一个try语句后可以写多个catch进行处理,如果异常正常处理,则最后的语句(try...catch...finally后的)会正常执行,若没有正常处理,则不会正常执行,但是finally中的语句无论怎样都会执行。
为了保证程序出现错误后可以正常执行完毕,可以采用多个catch处理,但是,实际出现的异常会是什么类型的,我们自己可能都不知道,如何保证写的catch都能cover所有异常呢?
为了分析Java中的异常处理流程,先看两个异常类的继承结构:
java.lang.ArithmeticException | java.lang.NumberFormatException |
---|---|
java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.ArithmeticException | java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.IllegalArgumentException java.lang.NumberFormatException |
可以发现,所有的异常类都是 java.lang.Throwable的子类,现在观察下Throwable类:
public class Throwable extends Object implements Serializable |
---|
其是Object的子类,从JDK1.0开始提供,但是Throwable下有两个子类,因此,开发中基本不会考虑Throwable处理。这里有个经典的面试题:
【面试题】:请解释Throwable下的Error和Exception的区别
因此,以后的开发中,异常处理能够处理 的最大父类就是Exception。
下面根据以上分析结论,分析下异常的处理流程:
通过上述分析,可发现,catch匹配异常,和方法传递很类似,安按照对象向上转型的原则,左右的子类对象都可以用父类接收,所以,实际上都可以用Exception进行处理。
实际开发中,如果开发团队有明确要求,则异常进行分开处理(便于定位查询是出了什么错误),若要求不明确,则使用Exception进行处理是最方便的。
执行某些代码时,用户该如何知道会产生哪些异常?Java中的throws关键字,明确的告诉用户执行哪一个方法时有可能会产生哪些异常,该关键字主要用于方法的声明处。
【举例】:观察throws关键字
class MyMath{
public static int div(int x, int y) throws Exception{
return x/y;
}
}
以上div方法中,要想执行该语句,就必须要进行异常的处理,此时编译无法通过。若程序中使用了throws声明,就必须强制使用try...catch进行异常处理操作。
使用throws后有一个传递的问题,主方法也是一个方法,所以主方法也可以使用throws,此时主方法不进行异常处理,而是交给被调用处处理。主方法之上是交由JVM默认处理,所以一般来说,Java代码主方法中应该把异常全部处理完成。
目前所有的异常对象都是由Java进行实例化对象的,我们处理的只是捕获异常对象,但是Java中允许用户自己去实例化异常类对象,若要抛出这个对象,就要用关键字throw。
【举例】:手工抛出异常
以上直接手工抛出异常,编译不通过,只要出现了throw,就表示代码产生了异常,此时只能:或者方法上使用throws继续抛出,或者手工异常处理try...catch。
try {
throw new Exception("我跑出的异常");
} catch (Exception e) {
e.printStackTrace();
}
【面试题】:情请解释throw与throws的区别?
对于异常的处理已经学习过了:try、catch、finally、throw、throws这些关键字,finally、throw看似没什么用,但是用的时候一般都是一起用的。举个栗子,看下非常重要的异常处理模型。
假设定义一个除法计算的方法,要求:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
System.out.println(MyMath.div(10,0));
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyMath{
public static int div(int x, int y) throws Exception{//交给被调用处处理
int result = 0;
System.out.println("计算开始");
result = x/y;
System.out.println("计算结束");
return result;
}
}
以上程序输出,没有输出 计算结束,因为result=x/y 抛出异常,在被调用处进行处理,程序就over了。
【举例】:加入异常控制(非常重要的异常处理模型)
class MyMath{
public static int div(int x, int y) throws Exception{//交给被调用处处理
int result = 0;
System.out.println("计算开始");
try{
result = x/y;
}catch (Exception e){
e.printStackTrace();
throw e;//继续向上抛出异常
}finally {
System.out.println("计算结束");
}
return result;
}
}
实际开发中,一定会牵扯到资源的使用,例如:文件、数据库,数据库操作前一定要打开,关闭后一定要关闭。但是以上给出的异常处理模型可以简化:try...finally,但是这种不太标准,不建议使用。
class MyMath{
public static int div(int x, int y) throws Exception{//交给被调用处处理
int result = 0;
System.out.println("计算开始");
try{
result = x/y;
}finally {
System.out.println("计算结束");
}
return result;
}
}
观察如下代码:
int num = Integer.parseInt("10");
System.out.println(num*num);
运行OK,但是,打开Integer类中的parseInt()方法来看:
public static int parseInt(String s) throws NumberFormatException |
---|
方法声明使用了throws关键字,但是我们 程序代码中没有进行异常处理,也能编译通过,运行正常。WHY???先观察下NumberFormatException类的继承结构。NumberFormatException 是RuntimeException的子类,所以该异常属于选择性处理,即使不处理,程序编译时也不会崩溃,但是执行时会出错。
java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.IllegalArgumentException java.lang.NumberFormatException |
---|
【面试题】:请解释Exception 与RuntimeException的子类?
【面试题】:请举出常见的RuntimeException 异常?
JDK1.4开始增加了新的关键字,此部分内容了解即可,没什么用~ 断言,指的是在程序编写过程中确定代码执行到某行之后,数据一定是某个期待的内容。
【举例】:观察断言
int num = 10;
assert num==100 : "断言错误,num不是100";
System.out.println(num);
以上,程序没有执行断言语句,对于断言,默认情况下是不会启用的,只有在程序运行时增加了一些配置参数,才会使用。
Java中的异常类之中提供有大量的类型,但是这些提供的类型几乎都是语法有关的异常类型,缺少业务类型,比如:输入某个人的成绩,成绩超过100,那么就应该产生一个与之对应的异常处理。这样的异常需要开发者进行自定义,所以要用到自定义异常类。
对于异常类型主要有两种:Exception、RuntimeException。
【举例】:设计一个成绩的异常
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
double score = 101.1;
if(score > 100){
try {
throw new ScoreException("成绩大于100分");
} catch (ScoreException e) {
e.printStackTrace();
}
}
}
}
class ScoreException extends Exception{
public ScoreException(String msg){
super(msg);
}
}
1)几种组合:try...catch、try...catch...finally...throws...throw;
2)RuntimeException与Exception的区别;
3)异常的处理流程:可以看成是引用对象的传递过程。
______________________________________________________________________________________
本文为博主原创文章,转载请注明出处,若本文对您有些许帮助,关注/评论/点赞就是对我最大的支持,多谢!