异常机制总结

1.什么是异常

异常是Java中提供的一种识别及响应错误情况的一致性机制。有效地异常处理能使程序更加健壮、易于调试。

        1.1异常原因

  1. 用户输入了非法数据
  2. 要打开的文件不存在
  3. 网络通信时连接中断
  4. JVM内存溢出
  5. 这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。

例子

import java.io.FileInputStream;
import java.io.FileNotFoundException;

//异常分类:
//      空指针
//      下标越界
//      栈内存溢出
//      类型转换异常
//     异常处理的两种方式
//不能比父类有更宽泛的异常
//异常发生的原因有很多,尤其是用户输入和要打开的资源不存在
//这些异常出错后,后导致程序生命周期终止执行,从错误代码开始,之后的代码就不会执行
//java中有一个专门模拟异常的类,就是Throwable,所有异常都继承这个类
public class _1_Exception {
    public static void main(String[] args) {
        try {
            FileInputStream fis = new FileInputStream("D:/xxx");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

}

2.系统异常分类

 

3.error 系统内部错误

        3.1什么是error

系统内部错误,这类错误由系统进行处理,程序本身无需捕获处理。 
比如:OOM(内存溢出错误)、VirtualMachineError(虚拟机错误)、StackOverflowError(堆栈溢出错误)等,一般发生这种情况,JVM会选择终止程序。

4.Exception类

        4.1什么是Exception

Exception是所有异常类的父类。分为非RuntimeException和RuntimeException 。

  1. 非RuntimeException 
    指程序编译时需要捕获或处理的异常,如IOException、自定义异常等。属于checked异常。
  2. RuntimeException 
    指程序编译时不需要捕获或处理的异常,如:NullPointerException等。属于unchecked异常。一般是由程序员粗心导致的。如空指针异常、数组越界、类型转换异常等。

5.Exception类中的方法

Exception类和其他普通类一样,有自己的属性和方法,为我们提供异常的相关信息。常用的方法有:

方法

说明

public String getMessage()

返回关于发生的异常的详细信息。这个消息在Throwable类的构造函数中初始化了。

public void printStackTrace()

打印toString()结果和栈层次到System.err,即错误输出流。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
// 异常处理的两种方式
//         		1 throws  : 抛出异常,告诉调用处,这里可能有什么问题
//         				如果你把异常抛给了调用处.那么调用处要么也抛出去,要么解决
//        		2 try...catch... : 解决异常
//
//        			try{
//         				高风险代码;
//         			}catch(异常类型 变量){
//         				解决方案;
//         			}
public class _2_Exception {
    public static void main(String[] args) {
        try {
            //打开资源文件
            FileInputStream fis = new FileInputStream("E:/asd");
        } catch (FileNotFoundException e) {
            //打印错误的追踪栈帧,适用于排错
            e.printStackTrace();
            //获取错误信息,适合响应给用户
            String msg = e.getMessage();
            System.out.println(msg);
        }
        System.out.println(456);
    }
}

6.异常捕获与处理

        6.1异常如何捕获处理   

程序在执行时如果发生异常,会自动的生成一个异常类对象,并提交给JAVA运行环境,这个过程称为抛出异常。程序也可以自行抛出异常。 
当出JAVA运行环境接收到异常对象时,会寻找能处理这个异常的代码并按程序进行相关处理,这个过程称为捕获异常

        6.2  try-catch

【语法格式】

try{

     有潜在异常抛出的语句组

}catch(异常类名 异常形参){

     异常处理语句组    

}catch(异常类名 异常形参){

     异常处理语句组

}catch(异常类名 异常形参){

     异常处理语句组

}catch(异常类名 异常形参){

     异常处理语句组

}finally{

     语句组

}

其中: 
1. try用来捕获语句组中的异常 
2. catch用来处理异常可以有一个或多个,而且至少要有一个catch语句或finally语句 
3. finally中的语句组无论是否有异常都会执行

常用捕捉异常方式 
1. try…catch try…finally 
2. try…catch…finally 
3. try…catch1…catch2…finally(体现异常出现的大小顺序) 
多重catch处理异常,大异常类在后,小异常类在前。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
// 异常处理的两种方式
//         		1 throws  : 抛出异常,告诉调用处,这里可能有什么问题
//         				如果你把异常抛给了调用处.那么调用处要么也抛出去,要么解决
//        		2 try...catch... : 解决异常
//
//        			try{
//         				高风险代码;
//         			}catch(异常类型 变量){
//         				解决方案;
//         			}
public class _2_Exception {
    public static void main(String[] args) {
        try {
            //打开资源文件
            FileInputStream fis = new FileInputStream("E:/asd");
        } catch (FileNotFoundException e) {
            //打印错误的追踪栈帧,适用于排错
            e.printStackTrace();
            //获取错误信息,适合响应给用户
            String msg = e.getMessage();
            System.out.println(msg);
        }
        System.out.println(456);
    }
}

 多个try-catch

import java.io.FileInputStream;
import java.io.FileNotFoundException;
//catch中异常类型 不能有继承关系,需要子类到父类
//抛异常可以同时抛出多个,逗号隔开,没有先后顺序
public class _5_Exception {
    public static void main(String[] args) {
        try {
            FileInputStream fis = new FileInputStream("");
        } catch (FileNotFoundException e) {
            System.out.println("找不到文件");
        }catch (NullPointerException e) {
            System.out.println("空指针异常");
        }catch (Exception e) {
            System.out.println("其他异常");
        }
    }
}

 try-catch-finally

//finally :必须执行的语句块(如打开资源需要关闭)

//finally不能单独出现,必须和try 一起使用或者try_catch一起使用

//finally语句块只有一种不执行情况,那就是关闭虚拟机System.exit(0);

public class _7_Exception {
    public static void main(String[] args) {
        try {
            int a = 0;
            int b = 5;
            int c = b/a;
            System.out.println(c);
        } catch (Exception e) {
            e.printStackTrace();
            return;//终止方法执行
        } finally {
            //finally一定会执行
            System.out.println("2222");
        }
//        这个执行不到,是因为上面有return
        System.out.println("1111");
    }
}

final、finalize和finally的区别

1.final是一个关键字。表示最终的,不可变的。

    final修饰的变量无法重新赋值。
   final修饰的类无法继承
   final修饰的方法无法覆盖

2.finalize()方法JVM的GC垃圾回收器负责调用

当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法。如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法中(留遗嘱)

  - finalize()是Object类中的一个方法。作为方法名出现
  - 所以finalize是一个标识符。
3.finally是一个关键字,和try联合使用,使用在异常处理机制中。

   - 在finally语句块中的代码是一定会执行的。
 

易错点finally中的return

public class _8_Exception {
    public static void main(String[] args) {
        int resule = m1();//11========
        System.out.println(resule);//10
    }

    public static int m1() {
        int i = 10;
        try {
            // 因为finally中有return,并且优先级是比较高的
            // 所以在编译的时候 就把这里的return去掉了,只有i++
            return i++;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println(i +"========");
        }
        //返回的是成员变量
        return i;
    }
}

finally的作用

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class _9_Exception {
    public static void main(String[] args) {
//        扩展作用域
        FileInputStream fis = null;
        try {
            //打开资源
            fis = new FileInputStream("xxx");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            //关键在下面关闭资源,避免缓存过大
            try {
                //做判断是否打开资源,如果打开了,就关闭
                if (fis != null){
                    fis.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

自动关闭资源

//1.7特性 自动关闭资源
public class _10_Exception {
    public static void main(String[] args) {
        //自动关闭资源
        try (FileInputStream fis = new FileInputStream("xxx");){

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

 

异常与方法覆盖

在方法覆盖时,重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少(更小)的异常

class Animal{
    public void doSome(){

    }
	public void doOther() throws Exception{

	}
}

class Cat extends Animal{

    //编译错误
    /*public void doSome throws Exception() {

    }*/

    //编译正常
    /* public void doOther(){

    }*/

    //编译正常
/*    public void doOther() throws Exception {

    }*/

    //编译正常
    public void doOther() throws NullPointerException{

    }
}

     6.3  throws 与throw的区别 

throws【语法格式】 
修饰符 返回类型 方法名(参数列表) throws 异常类名列表

子类继承父类,并重写父类的方法时,若方法中抛出异常,则要求:子类方法抛出异常只能是父类方法抛出的异常的同类或子类。
演示子类重写父类方法时,抛出的异常不能比父类抛出的异常大。

import java.io.FileNotFoundException;
import java.io.IOException;
//throws 抛出异常,并不会处理异常,是一种提醒机制
//空指针运行时异常RuntimeException
//谁调用抛给谁    throws是抛异常,并不会解决异常,一般用于类库端(被调用 这个类 )
//而try...catch是解决异常,一般用于客户端
public class _3_Exception {
}
class A{
    public void m1() throws IOException {

    }
}
class B extends A{
    // 方法覆写,不能比原方法拥有更宽泛的异常
    //  抛出的异常类,可以是父类方法中抛出的类,也可以是对应的子类 , 但是不能是它的父类
    // 父类抛出一个异常A , 那么子类 要么还抛出A , 要么抛出A的子类, 要么不抛异常 , 但是不能是A的父类
    @Override
    public void m1() throws FileNotFoundException{

    }
}

throw【语法格式】 它的作用是抛出异常,抛出一个异常类的实例化对象。
throw new XXXException();

  1. 这种抛出异常的方式一般在满足某条件时主动抛出,即满足用户定义的逻辑错误发生时执行。
  2. 含有throw语句的方法,或者调用其他类的有异常抛出的方法时,必须在定义方法时,在方法头中增加throws异常类名列表。
  3. 使用throws关键字声明的方法表示此方法不处理异常,而交给方法调用处进行处理。

        6.4   自定义异常

                6.41什么是自定义异常

系统定义的异常主要用来处理系统可以预见的常见运行错误,对于某个应用所特有的运行错误,需要编程人员根据特殊逻辑来创建自己的异常类。

【语法格式】 
public class 自定义异常类名 extends Exception{ … }

 

UserException

//继承一个已有的异常类
//      判断编译时异常还是运行时异常
//      运行时异常需要继承RuntimeException
//      否则就继承大类Exception
//类名   公共的有参构造和无参构造
//      有参构造传入字符串,方法中将字符串传递给父类
public class _11_UserException extends Exception{
    public _11_UserException(){

    }
    public _11_UserException(String msg){
        super(msg);
    }
}

UserService

public class _12_UserService {
    public static void login(String username,String password) throws _11_UserException{
        if (username.equals("admin")){
            if (password.equals("root")){

            }else {
                throw new _11_UserException("密码不正确");

            }
            }else {
                throw new _11_UserException("用户名不正确");

        }
    }
}

 

Client

import java.util.Scanner;

//客户端
public class _13_Client {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名和密码");
        String username = scanner.next();
        String password = scanner.next();
        try {
            _12_UserService.login(username,password);
            System.out.println("登录成功");
        } catch (_11_UserException e) {
            e.printStackTrace();
            //打印异常信息
            System.out.println(e.getMessage());
        }
    }
}

Test

public class _14_Test {
    public static void main(String[] args) throws _11_UserException{
        throw new _11_UserException("asdfdgf");
    }
}

小练习

import java.util.Random;

/**
 * 生成五个不同的数 [1~5]
 * 		不能保证每次生成的数据是不同的
 * 		创建一个长度为5的数组,把生成的数据放到数组中,并保证数据不重复
 *
 * 1 数组存储 长度5
 * 			动态声明
 * 
 * 2 随机数生成 1-5
 * 			1 生成器
 * 			2 nextInt(5)+1
 * 
 * 3 生成数据放到数组中
 * 		1 保存以添加元素的个数
 * 		2 循环 , 放满5个 就不执行了
 * 		3 生成随机数 , nextInt(5)+1 
 * 		4 和 数组中 已有元素进行比较
 * 				遍历数组, 用生成的这个数据 和 已添加的数据进行比较
 * 				如果没有重复的,放进去,个数+1 , 有重复的,跳过,继续生成
 * 
 * 4 遍历测试
 * 
 */
public class Test_01 {
	public static void main(String[] args) {
		
		System.out.println((char)(Math.random()*26+97));
		// 数组存储 长度5
		int[] arr = new int[5];
		// 生成器
		Random r = new Random();
		// 保存以添加元素的个数
		int length = 0;
		while (length < 5) {
			// 生成随机数 , nextInt(5)+1
			int temp = r.nextInt(5) + 1;
			// 和 数组中 已有元素进行比较
			// 假设该数据没有重复
			boolean flag = false;
			for (int i = 0; i < length; i++) {
				// 有重复的,跳过,继续生成
				if (arr[i] == temp) {
					flag = true;
					break;
				}
			}
			if (!flag) {
				// 到这里说明不重复
				// 如果没有重复的,放进去,个数+1
				arr[length] = temp;
				length++;
			}
		}

		// 遍历测试
		for (int i : arr) {
			System.out.println(i);
		}
	}
}

异常机制思维导图

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

让火车在天上飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值