Java异常(一)


1、Java异常


  • 异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”
  • Java中的异常用于处理非预期的情况,如文件没找到,网络错误,非法的参数

2、两类Java异常事件


Error: JVM系统内部错误、资源耗尽等严重情况

Exception: 其它因编程错误或偶然的外在因素导致的一般性问题。

例如:

  • 空指针访问

  • 试图读取不存在的文件

  • 网络连接中断

3、几种异常分析举例


ArrayIndexOutOfBoundsException:数组下标越界异常

指数组下标超过初始化的范围。

代码示例如下:

			String[] strs=new String[] { "a","b","c"};
			for(int i = 0; i < strs.length+1; i++) {//i=0,1,2,3
			//数组越界异常:java.lang.ArrayIndexOutOfBoundsException: 3
			//这里的3就是异常下标
			System.out.println(strs[i]);
			//数组只有三个元素数组下标为0,1,2
			//没有第四个元素,当输出strs[3]时没有
			//所以当取到3时会出现数组下标越界

执行结果:

image-20220328152739788

NullPointerException:空指针异常

引用指向的不是对象,是一个空指针

代码示例如下:

		//正确的是A a=new A();
		A a = null;//在这里指向,引用变量a没有指向任何对象,指向的是null
		System.out.println(a.i);
		//什么都没有指向i的值
		//这里就会空指针异常
		class A{
			int i;
		}	

执行结果:

image-20220328155117136

ArithmeticException:数学类异常

指不按数学规范计算,导致的错误结果的异常。

代码示例如下:

		int i=0;
		//除法分母不能等于0
		System.out.println(3/i);

执行结果:

image-20220328155743196

3、Java异常类层次


RuntimeException:运行时异常

  • 错误的类型转换

  • 数组下标越界

  • 空指针访问

IOExeption:输入输出异常

  • 从一个不存在的文件中读取数据

  • 越过文件结尾继续读取EOFException

  • 连接一个不存在的URL

image-20220328190428659

4、异常处理


如果发生任何一种异常都会导致程序中断,影响后续就像下面的代码,不会执行输出Ok的道理。

示例代码:

		int i=0;
		System.out.println(3/i);
		System.out.println("ok");

抓抛模型


Java提供的是异常处理的抓抛模型

*** 注:抓抛模型说白了就是,抓(catch)是捕获的意思,抛(throws)是抛出的意思。***

Java程序的执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。

如果一个方法内抛出异常,该异常会被抛到调用方法中。如果异常没有在调用方法中处理,它继续被抛给这个调用方法的调用者。

这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。

如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。

程序员通常只能处理Exception,而对Error无能为力。

捕获异常处理:


try catch用法:

? 一般catch经常和try搭配使用,用try{}来括住一段有可能出现异常的代码段

? catch括号内当不知道捕获的是什么类型的异常时,可以选择所有的异常的父类Exception先进行捕获。

代码如下:

		int i=0;
		try {
			System.out.println(3/i);
		} catch (Exception e) {
			e.printStackTrace();//打印异常信息在程序中出错的位置及原因
            System.out.println(e.getMessage());//打印异常原因
		}
		System.out.println("ok");

运行结果:

image-20220328163542354

从结果来看,异常原因被抛出并且打印出来了,后续程序也可正常执行。

try catch finally用法:

在原来try catch的基础上多加一个finally{}程序块

	int i=0;
	try {
		System.out.println(1);
		System.out.println(3/i);
		System.out.println(2);
	} catch (Exception e) {
		System.out.println(3);
	}finally {
		System.out.println(4);
	}
	System.out.println("ok");
}

运行结果:

image-20220328200157017

从以上可以看到并没有输出2,是因为在输出语句之前出现了异常,捕捉到异常后,直接转到catch程序块执行输出3,跳过了输出2。

当catch有多个语句程序时,只优先执行第一句的异常,不会同时捕捉多个异常。

代码:

		String[] strs= new String[] {"a","b"};
		A a=null;
		try {
			System.out.println(strs[2]);
			System.out.println(a.i);
		} catch (ArrayIndexOutOfBoundsException e) {
			// TODO: handle exception
			System.out.println(e.getMessage());
			//捕获数组异常
			e.printStackTrace();
		}
		catch (NullPointerException e1) {
			// TODO: handle exception
			System.out.println(e1.getMessage());
			//捕获空指针异常
			e1.printStackTrace();
		}
		System.out.println("===================");
		

运行结果:

image-20220328202326814

try catch没必要明确知道异常的具体类型,直接写

catch(Exception e){
	//处理异常操作
	e.printStackTrace();
    //可以使用打印异常操作,打印异常原因
    e.getMessage();
}

常常使用getMessage()方法和printStackTrace(),来用于捕获到的异常,进行打印异常事件的信息操作,打印跟踪执行堆栈的内容等操作。

声明抛出异常:


throws用法:

在使用throws方法之前,我们可以构想一个流程,加上之前学的捕获异常,我们可以先抛出异常在进行捕获

创建的对象调用方法的同时用throws进行抛出,再到主程序块进行捕获处理,

代码如下:

public class Test1 {
	public static void main(String[] args)  {//也可以在main方法抛出异常
		//main方法抛出异常直接抛到虚拟机上去了,在程序中无法进行处理
		B b = new B();
		try {
			b.test();
			//throws在方法块抛出异常,
			//在调用部分进行捕获处理
		} catch (Exception e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	
	
	}
}
class B{
	int i;
	public void test() throws Exception{//可以使用throws在代码这抛出异常,在调用方捕获处理
		B b=null;
		System.out.println(b.i);
	}
}
	

运行结果:

image-20220328205033329

5、重写方法声明抛出异常的原则


当子类重写父类的方法时,子类不能抛出比父类方法更大范围的异常,这里如果子类C抛出Exception就会报错。

class B{
	int i;
	//NullPointerException的父类是RuntimeException
	public void test() throws RuntimeException{//可以使用throws在代码这抛出异常,在调用方捕获处理
		B b=null;
		System.out.println(b.i);
	}
}
class C extends B{

	@Override
	public void test() throws NullPointerException {
		//重写方法不能抛出比被重写更大的异常类型
		// TODO 自动生成的方法存根
		super.test();
	}
}

6、人工抛出异常


Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要人工创建并抛出

public class Test1 {
	public static void main(String[] args)  {
		B b = new B();
		try {
			b.test1(-100);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
}
class B{
	int i;
	int age;
	//NullPointerException的父类是Exception
	public void test() throws NullPointerException{//可以使用throws在代码这抛出异常,在调用方捕获处理
		B b=null;
		System.out.println(b.i);
	}
	public void test1(int age) throws Exception{
		if (age>=0 && age<=180) {
			this.age=age;
			System.out.println("年龄是:"+this.age);
		}else {
			throw new Exception("这个年龄不在0-150之间");
		}	
	}
}

运行结果:

image-20220328213003834

创建用户自定义异常类


java提供的异常的类一般是够用的,只有特殊情况可能需要自己编写异常类,并且这种情况及其少见。

public class Test1 {
	public static void main(String[] args) throws MyException  {//可以在main方法抛出异常
		B b = new B();
		try {
//			b.test1(-100);
			b.test2(-100);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
}
class B{
	int i;
	int age;
	//NullPointerException的父类是Exception
	public void test() throws NullPointerException{//可以使用throws在代码这抛出异常,在调用方捕获处理
		B b=null;
		System.out.println(b.i);
	}
	public void test1(int age) throws Exception{
		if (age>=0 && age<=180) {
			this.age=age;
			System.out.println("年龄是:"+this.age);
		}else {
			throw new Exception("这个年龄不在0-150之间");
		}	
	}
	public void test2(int age) throws MyException {
		if (age>=0 && age<=180) {
			this.age=age;
			System.out.println("年龄是:"+this.age);
		}else {
			throw new MyException("这个年龄不在0-150之间");
		}	
	}
}
class MyException extends Exception{
	public MyException(String msg) {
		super(msg);
	}
}

运行结果

image-20220328222504978