1. 异常的产生
异常是导致程序中断执行的一种指令流,异常一旦出现且没有对其进行合理的处理,程序就中断执行。
范例:不产生异常的代码
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("1.开始除法计算");
System.out.println("2.计算 " + (10/2));
System.out.println("3.结束除法计算");
}
}
输出显示:
1.开始除法计算
2.计算 5
3.结束除法计算
范例:产生异常
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("1.开始除法计算");
//此行代码产生异常
System.out.println("2.计算 " + (10 / 0));
System.out.println("3.结束除法计算");
}
}
输出显示:
1.开始除法计算
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExceptionDemo.main(ExceptionDemo.java:5)
异常一旦发生,产生异常的语句及之后的语句都不再执行,默认输出异常信息后,程序自动结束执行。
我们要做的就是:即使出现了异常,也应该让程序正确的执行完毕。
2. 处理异常
如果想要进行异常的处理,在Java之中提供了三个关键字:try、catch、finally,而这三个关键字的使用语法如下:
//“[]” 表示有可能使用到
try {
//有可能出现异常的语句
} [ catch(异常类型 对象){
//异常处理
}catch(异常类型 对象){
//异常处理
}...] [finally {
//不管是否出现异常,都执行的代码
}]
范例:应用异常处理try...catch
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("1.开始除法计算");
try {
System.out.println("2.计算 " + (10 / 0));
} catch (ArithmeticException e){
e.printStackTrace();
}
System.out.println("3.结束除法计算");
}
}
输出显示:
1.开始除法计算
java.lang.ArithmeticException: / by zero
at ExceptionDemo.main(ExceptionDemo.java:6)
3.结束除法计算
由于使用了异常处理,即使程序出现了异常,也可以正常的执行完毕。而且使用异常类中提供的printStackTrace()方法,可以完整的输出异常信息。
范例:使用try...catch...finally
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("1.开始除法计算");
try {
System.out.println("2.计算 " + (10 / 0));
} catch (ArithmeticException e){
e.printStackTrace();
} finally {
System.out.println("不管是否有异常,都执行此语句!");
}
System.out.println("3.结束除法计算");
}
}
输出显示:
1.开始除法计算
java.lang.ArithmeticException: / by zero
at ExceptionDemo.main(ExceptionDemo.java:5)
不管是否有异常,都执行此语句!
3.结束除法计算
3. 异常的处理流程(核心)
首先观察两个异常类的继承结构:
观察可以发现所有的异常类都是Throwable的子类,而在Throwable下有两个子类:
Error 和 Exception
- Error :指的是JVM错误,即:此时的程序还没有执行,用户还无法处理;
- Exception :指的是程序运行中产生的异常,用户可以处理。
也就是所谓的异常处理指的就是所有的Exception以及它的子类异常。
面试题:Java中的异常处理流程
范例:使用Exception处理异常
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("1.开始除法计算");
try {
int x = Integer.parseInt(args[0]);
int y = Integer.parseInt(args[1]);
System.out.println("2.计算 " + (x / y));
System.out.println("**************");
} catch (Exception e){
e.printStackTrace();
} finally {
System.out.println("不管是否有异常,都执行此语句!");
}
System.out.println("3.结束除法计算");
}
}
所有的异常都使用了Exception进行处理,所以在程序之中不用再去关心到底使用哪一个异常。
注意:
- 在编写多个catch捕获异常的时候,捕获范围大的异常一定要放在捕获异常范围小的异常之后,否则编译错误。
- 虽然直接捕获Exception比较方便,但是这样也不好,因为这样所有的异常都会安装同一方式处理。
4. throws关键字
throws关键字主要用于方法声明上,指的是当方法之中出现异常后交由被调用处来进行处理。
范例:使用throws
class MyMath {
//存在throws关键字,表示此方法里面产生的异常交给调用处处理
public static int div(int x , int y) throws Exception {
return x / y ;
}
}
public class ThrowsDemo {
public static void main(String[] args) {
try {
System.out.println(MyMath.div(10 , 2));
} catch (Exception e) {
e.printStackTrace();
}
}
}
调用了具有throws声明的方法之后,不管操作是否出现异常,都必须使用try...catch来进行异常的处理。
5. throw关键字
在程序之中直接使用throw手工抛出一个异常类的实例化对象。
范例:手工抛出异常
public class ThrowDemo {
public static void main(String[] args) {
try {
throw new Exception("自己定义的异常");
} catch(Exception e) {
e.printStackTrace();
}
}
}
输出显示:
java.lang.Exception: 自己定义的异常
at ThrowDemo.main(ThrowDemo.java:4)
面试题:throws 和 throw的区别
- throws:在方法的声明上使用,表示此方法在调用时必须处理异常;
- throw:指的是在方法中人为抛出一个异常类对象(这个异常类对象可能是自己实例化或是抛出已知存在)。
6. 重要的代码模型:异常的使用格式
需求:要求定义一个div()方法,在进行计算之前打印提示信息,计算结束也打印提示信息,如果在计算之中产生了异常,则交给被调用处进行处理。
范例:不出错的代码
class MyMath {
public static int div(int x , int y) {
int result = 0;
System.out.println("*** 1. 计算开始 ***");
result = x / y;
System.out.println("*** 1. 计算结束 ***");
return result;
}
}
public class ThrowsDemo {
public static void main(String[] args) {
System.out.println(MyMath.div(10 , 2));
}
}
但是以上代码中的除法操作不一定永远都正常完成,所以应该进行合理的处理。首先,如果方法出现异常,必须交由调用处处理,所以应该在方法上使用throws抛出
class MyMath {
//存在throws关键字,表示此方法里面产生的异常交给调用处处理
public static int div(int x , int y) throws Exception {
int result = 0;
System.out.println("*** 1. 计算开始 ***");
result = x / y;
System.out.println("*** 1. 计算结束 ***");
return result;
}
}
public class ThrowsDemo {
public static void main(String[] args) {
try {
System.out.println(MyMath.div(10 , 2));
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果以上代码真的出错,程序的有些内容就不执行了,所以修改如下:
class MyMath {
//存在throws关键字,表示此方法里面产生的异常交给调用处处理
public static int div(int x , int y) throws Exception {
int result = 0;
System.out.println("*** 1. 计算开始 ***");
try {
result = x / y;
} catch (Exception e) {
throw e; //继续抛异常
} finally {
System.out.println("*** 1. 计算结束 ***");
}
return result;
}
}
public class ThrowsDemo {
public static void main(String[] args) {
try {
System.out.println(MyMath.div(10 , 0));
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出显示:
*** 1. 计算开始 ***
*** 1. 计算结束 ***
java.lang.ArithmeticException: / by zero
at MyMath.div(ThrowsDemo.java:7)
at ThrowsDemo.main(ThrowsDemo.java:19)
7. RuntimeException 类
先观察一段代码:
public class RuntimeExceptionDemo {
public static void main(String[] args) {
int temp = Integer.parseInt("100");
System.out.println(temp); //输出100
}
}
在看一下parseInt()方法的定义:
public static int parseInt(String s) throws NumberFormatException
此时parseInt()方法上抛出了NumberFormatException,按理说,应该进行强制性的异常捕获,但是现在并没有强制性操作,所以来看下NumberFormatException的继承结构:
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException → 运行时异常
java.lang.IllegalArgumentException
java.lang.NumberFormatException
在Java里面为了方便用户代码的编写,专门提供了RuntimeException类,其特征为:程序在编译的时候不会强制性要求用户处理异常,用户可以根据需求选择性的进行处理,如果没有处理又发生了异常,则交给JVM默认处理。
面试题:Exception 和 RuntimeException的区别?列举几个常见的RuntimeException子类:
- Exception是RuntimeException的父类;
- 使用Exception定义的异常必须要被处理,而RuntimeException的异常可以选择性处理:
- 常见的RuntimeException:ArithmeticException、NullPointerException、ClassCastException。
8. assert关键字—断言(了解)
assert关键字是在JDK1.4的时候引入的,其主要的功能就是进行断言。断言:指的是程序执行到某行代码处判断是否是预期的结果。
范例:观察断言
public class AssertDemo {
public static void main(String[] args) {
int num = 10;
//中间可能经过了多行代码操作num的内容
//期望中的内容是20
assert num == 20 : "num的内容不是20";
System.out.println("num = " + num);
}
}
正常执行输出显示:
num = 10
启用断言执行:java -ea AssertDemo
Exception in thread "main" java.lang.AssertionError: num的内容不是20
at AssertDemo.main(AssertDemo.java:6)
9. 自定义异常
Java本身提供了大量的异常,但是这些异常实际工作中并不够去使用,所以就需要用户自定义异常类。如果开发自定义的异常类可以选择继承Exception或者RuntimeException类。
范例:定义AddException
class AddException extends Exception{
public AddException(String msg) {
super(msg);
}
}
public class AddExceptionDemo{
public static void main(String[] args) {
int num = 20;
try {
if (num > 0) { //出现错误,应该产生异常
throw new AddException("数值传递过大");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上代码知识介绍自定义异常的形式,但是并不能说明自定义异常的实际使用。
总结
- Exception的父类是Throwable,但是在编写代码的时候尽量不要使用Throwable,因为Throwable类有子类Error,用户能处理的只有Exception类
- 异常处理的标准格式:try、catch、finally、throw、throws;
- RuntimeException与Exception的区别。