概念
1. 什么是异常:异常是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序。
2. 什么是异常处理:异常处理是编程语言的一种机制,对可能出现的问题进行预处理,异常处理完毕后,程序可以继续运行,增强系统的健壮性和安全性。
3. 异常处理的必要性:异常处理用于解决一些程序无法掌控,但又必须面对的情况。为了程序能继续运行,就需要把这些情况进行异常处理。异常处理的方法通常有以下几种:
1) 将异常通知给开发人员、运维人员或用户
2) 因为异常中断的程序以适当的方式继续运行,或者退出
3) 保存用户的当前操作,或者进行数据回滚
4) 释放资源
4. Java 编程语言提供了异常处理机制为程序提供了错误处理的能力
异常分类
1) Throwable 类是 Java 异常类型的顶层父类,一个对象只有是 Throwable类的实例,才是一个异常对象,才能被异常处理机制识别,位于java.lang包中。
2) 按照错误严重性,从 Throwale 类中衍生出 Error 和 Exception 两大派系
a) Error(错误):程序在执行过程中所遇到的硬件或系统的错误。错误对程序而言是致命的,将导致程序无法运行。不允许捕获。当发生 Error 时,只能依靠外界干预。常见错误: StackOverflowError、OutOfMemoryError等。
b) Exception(异常):是程序运行过程中,可以预料的意外情况。比如空指针,数组下标越界。异常出现可以被捕获处理掉,使程序继续运行。
public class Demo {
public static void main(String[] args) {
//异常:可以处理
// int[] arr = {3,2,4,5};
// System.out.println("arr[4]:"+arr[4]);//java.lang.ArrayIndexOutOfBoundsException: 4
//错误:不能处理
//int[] arr2 = new int[1024*1024*1024];//java.lang.OutOfMemoryError: Java heap space
//异常:检查异常和运行时异常
int div = 10/0;//java.lang.ArithmeticException: / by zero//编译器不检查的异常
//编译器能检查出来:检查异常
//FileInputStream fis = new FileInputStream("d:\\hello.txt");
}
}
3) Exception:又分为编译时异常和运行时异常。
RuntimeException:运行时异常,可处理,可不处理。
CheckedException:检查时异常,必须处理
a) 运行时异常都是 RuntimeException 类及其子类, 这些异常是不检查的异常, 是在程序运行的时候可能会发生的, 所以程序可以捕捉, 也可以不捕捉。程序应该从逻辑角度去尽量避免。如:空指针、数组下标越界等
NullPointerException
ArrayIndexOutOfBoundsException//数组越界
ArithemicException
ClassCastException
NumberFormatException
b) 编译时异常也叫检查异常,是运行时异常以外的异常, 也是 Exception 及其子类, 这些异常从程序的角度来说是必须经过捕捉检查处理的, 否则不能通过编译. 如 IOException、SQLException 等。
FileNotFoundExcetpion
IOException
SQLException
import java.io.FileInputStream;
public class ExceptionDemo {
public static void main(String[] args) {
//异常:检查异常和运行时异常
try {
int div = 10 / 0;//java.lang.ArithmeticException: / by zero//编译器不检查的异常
FileInputStream fis = new FileInputStream("d:\\hello.txt");
System.out.println("----------------------");
}
// catch(ArithmeticException e){
// System.out.println("捕获了异常....");
// }
// catch (FileNotFoundException e) {
// e.printStackTrace();
// }
catch (Exception e) {
e.printStackTrace();//追踪信息
} finally {//可选的,可以有,可以没有
//无论是否产生异常,都会执行finally语句块里面的代码
System.out.println("finally语句块一定要执行....");
}
System.out.println("hello,world!!!");
System.out.println("hello,world!!!");
System.out.println("hello,world!!!");
//编译器能检查出来:检查异常
//FileInputStream fis = new FileInputStream("d:\\hello.txt");
}
}
4) 异常分类的结构图
异常产生和传递
异常产生
自动抛出异常:当程序在运行时遇到不符合规范的代码或结果时,会产生异常。
手动抛出异常:语法:throw new 异常类型(“实际参数”)。
产生异常结果:相当于遇到 return语句,导致程序因异常而终止。
异常传递
按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。
受查异常:throws 声明异常,修饰在方法参数列表后端。
运行时异常:因可处理可不处理,无需声明异常。
异常的处理
捕获异常:try,catch,finally
语法规则:
try{
//可能产生异常的代码
}catch(异常类型1 e){
//捕获异常的处理
}catch(异常类型2 e){
//捕获异常的处理
}finally{
//无论程序是否产生异常,此处的代码一定会被执行。
//比如说:释放资源,删除临时文件等。。。
}
注意点:
1.一个try可以匹配多个catch语句
2.如果try中产生了异常对象,那么会跳出try,进到相应的catch中处理异常,从上向下匹配。
3.如果是多个catch语句,那么小的异常捕获处理写前面,大的异常捕获处理写后面。
4.finally是可选的
声明异常 throws
方法级别上,向外抛出异常。
方法的声明上就要通过throws关键字声明抛出异常:
public static void test1(int i,int j)throws NullPointerException{
}
[修饰符1,修饰符2.。。] 返回值类型/void 方法名(参数列表) 异常的声明{
}
按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。
public static void test1() throws ArithmeticException{
int i=10;
int j =0;
int div = i/j;
System.out.println("div:"+div);
System.out.println("test1.....end.....");
}
public static void test2() throws ArithmeticException{
// try {
// test1();
// } catch (ArithmeticException e) {
// e.printStackTrace();
// }
test1();
System.out.println("test2......end....");
}
public static void test3() throws FileNotFoundException {
File file = new File("c:\\a.jpg");
FileInputStream fis = new FileInputStream(file);
}
public static void test4() throws Exception{
//FileNotFoundException
test3();//检查异常一定要处理,强制处理
}
public static void test5() throws Exception{
}
public static void test6(){
test5();
}
public static void main(String[] args) {
try {
test2();
} catch (ArithmeticException e) {
e.printStackTrace();
}
System.out.println("main......end......");
}
运行时异常的抛出,不一定要处理
检查异常的抛出,必须处理
Exception和RuntimeException的区别?
1.RuntimeException是Exception的子类。
2.Exception包含了受检异常,所以抛出Exception以及受检异常时,代码中一定要给与处理。如果抛出的是RuntimeException(运行时异常,非受检)以及它的子类异常,程序中不一定非要处理。
3.重写的时候,子类不能抛出比父类更大的异常
class Person{
public void eat() throws FileNotFoundException{
}
}
class Student extends Person{
@Override
public void eat() throws Exception{
}
}
public class Demo7 {
public void test(Person p){
p.eat();
}
public static void main(String[] args) {
}
}
throw 关键字
throw和throws的区别?
1.throws,用于定义方法的时候,声明该方法向外抛出异常。
2.throw,主动抛出一个异常的对象。打断程序的执行。配合trycatch,或者throws来使用。
Exception exception = new Exception("我自定义的异常。。");
try {
throw exception;//自己主动抛出的异常
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("main......end.....");
自定义异常
1) 上面的异常体系结构图都是系统自带的,系统自己处理,但是很多时候项目会出现特有问题,而这些问题并未被 Java 所描述并封装成对象,所以对于这些特有的问题可以按照封装的思想,将特有的问题进行自定义异常封装。要想创建自定义异常,需要继承 Throwable 或者他的子类 Exception。
2) 使用自定义异常类的步骤
异常类型名称望文生义,可在发生特定问题时抛出对应的异常。
常用构造方法:
无参数构造方法。
String message参数的构造方法。
public class AgeException extends RuntimeException{
public AgeException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace){
super(message, cause, enableSuppression, writableStackTrace);
}
public AgeException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public AgeException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}