目录
java中分为两大类异常:RuntimeException,运行时异常,非受检异常。和受检异常。
造出一个异常并将异常抛出Exception 受检异常,制造异常时必须抛出让调用者处理:
造出一个异常并将异常抛出RuntimeException 非受检异常,制造异常时可以不抛出,让调用者使用时处理:
try-catch-finally中,如果catch中return了,finally会执行吗:finally中的代码会执行。
try-catch-finally中,都有return代码,以谁的为最终返回值:finally
目标:
1.明确什么是异常。(重点)
2.能辨别出常见的异常及其含义。(熟悉)
3.理解异常对象产生的原理。(了解)当异常出现了,java把它变成一个对象,里边包含所有不对劲情况的信息,jvm将不对劲的信息封装成对象。
4.能处理异常。(重点)
5.能够自定义异常类型。(熟悉)
什么是异常:
程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行。
为什么要用try{}catch(){}:
用while()循环用if()判断一样可以处理异常,为什么一定要中try{}catch(){},因为这个时java官方所提供的规则,规范。用这种统一的规则可以放代码更容易阅读。且保持代码的清晰。
try{}catch(){}的执行原理:
1.一旦产生异常,则系统会产生一个异常类的实例化对象,如果产生的异常是ArrayIndexOutOfBoundsException,则会产生一个ArrayIndexOutOfBoundsException类型的对象。这个对象需要被处理需要被抓到,如果不处理,程序崩溃。
2.如果异常发生在try块里边,则会自动找到匹配的catch块语句去执行,如果没有在try块中,则会将异常抛出。
3.所有的catch块会根据参数匹配异常类的实例化对象,如果catch块类型和产生的类型一致,则catch进行处理。
Finally:
异常的统一出口,如果在try块中有1-7行代码,第3行代码出现异常,则4567行不会再执行,因为第3行代码出现异常会直接跳到相应的catch块去处理,处理完之后代码往下走不会再调回执行4567行。无论是否发生异常,finally里的代码都会作为trycatch语句块最后的收尾代码,一定会在最后执行。
int[] arr = {1, 2};
for (int i = 0; i <= arr.length; i++) {
try {
System.out.print(arr[i]);
//System.out.print(10 / 0);
System.out.println("不执行");
} catch (ArrayIndexOutOfBoundsException|ArithmeticException e) {
System.out.println("发生问题是一套处理方案");
}finally {
System.out.println("执行");
}
}
1不执行
执行
2不执行
执行
发生问题是一套处理方案
执行
异常体系结构:
java中分为两大类异常:RuntimeException,运行时异常,非受检异常。和受检异常。
一个简单的异常:
//简单的除法计算器
Scanner input = new Scanner(System.in);
在算数上除数不能为0
//如果除数为0则出现ArithmeticException异常,算数异常
System.out.println("请输入被除数:");
int x = input.nextInt();
System.out.println("请输入除数:");
int y = input.nextInt();
//传统处理方法
//运用while解决异常
while (y==0){
System.out.println("除数不能为0");
System.out.println("请重新输入除数:");
y = input.nextInt();
}
int z = x / y;
System.out.println("两数相除的结果是:" + z);
}
异常处理演示try{}catch(){}:
/**
* try {
* 捕获语句块
* }catch(异常类型 异常对象){
* }
* 按照这种方式可以保证程序不被中断,如果代码发生异常没有去处理,就会导致程序中断
*/
//简单的除法计算器
Scanner input = new Scanner(System.in);
//如果除数为0则出现ArithmeticException异常
System.out.println("请输入被除数:");
int x = input.nextInt();
System.out.println("请输入除数:");
int y = input.nextInt();
int z = 0;
try {
//如果除数为0则出现ArithmeticException异常
z = x / y;
} catch (ArithmeticException e) {
//这里代码一旦执行,24行一定发生异常
System.out.println("出现了异常");
}
System.out.println("两数相除的结果是:" + z);
再演示一个简单的异常:
/**
* 捕获异常,必须捕获的异常类型和发生的异常是匹配的才能被捕获到
* ArrayIndexOutOfBoundsException:数据下标越界异常
*/
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0; i <= arr.length; i++) {
try{
System.out.print(arr[i]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组下标越界异常");
//捕获异常,必须捕获的异常类型和发生的异常是匹配的才能被捕获到
}/*catch (ArithmeticException e){
System.out.println("数组下标越界异常");
}*/
}
多异常处理的三种格式:
1.通过多个catch完成:
try{}catch(){}catch(){}...
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0; i <= arr.length; i++) {
try {
System.out.print(arr[i]);
System.out.print(10 / 0);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界异常");
//捕获异常,必须捕获的异常类型和发生的异常是匹配的才能被捕获到
} catch (ArithmeticException e) {
System.out.println("算数异常");
}
}
2.通过|符号:
try{}catch(类型1|类型2 对象名){}
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0; i <= arr.length; i++) {
try {
System.out.print(arr[i]);
System.out.print(10 / 0);
} catch (ArrayIndexOutOfBoundsException|ArithmeticException e) {
System.out.println("发生问题是一套处理方案");
}
}
3.使用里氏代换原则,更大范围的异常来捕获
* 异常是有范围的概念的,有些异常之间是包含关系的,一种类型的异常的下边会分成好几十种不同的子类异常。
* 如果捕获的是更大范围的,可以用更大范围的异常类型去抓取。
int[] arr = {1, 2};
for (int i = 0; i <= arr.length; i++) {
try {
System.out.print(arr[i]);
//System.out.print(10 / 0);
System.out.println("不执行");
} catch (RuntimeException e) {
System.out.println("发生问题是一套处理方案");
}
}
异常的抛出:
int z = 0;
try {
z = haha(10, 0);
} catch (Exception e) {
//e.printStackTrace();
System.out.println("出现异常");
}
System.out.println(z);
}
/**
* 除法运算
* throws将异常抛给调用者
* ArithmeticException属于运行时异常,写出的代码不漂红
* Exception属于异常的大类,调用时代码飘红
*/
public static int haha(int x, int y) throws Exception {
return x / y;
}
造出一个异常并将异常抛出Exception 受检异常,制造异常时必须抛出让调用者处理:
Person p = new Person();
try {
p.setAge(-18);//当调用时会飘红,必须处理
} catch (Exception e) {
System.out.println("异常");
}
}
static class Person {
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) throws Exception {
if (age < 0) {
//制造一个异常
Exception e = new Exception("年龄异常");
//这行代码就是异常,因为Exception是受检异常异常要不throws要不自己处理
throw e;
}
this.age = age;
}
造出一个异常并将异常抛出RuntimeException 非受检异常,制造异常时可以不抛出,让调用者使用时处理:
Person2 p = new Person2();
p.setAge(-18);//调用时不会飘红,运行时会出现异常
}
static class Person2 {
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age){
if (age < 0) {
//制造一个异常
RuntimeException e = new RuntimeException("年龄异常");
//这行代码就是异常,因为是运行时异常,调用时运行才出现异常
throw e;
}
this.age = age;
}
面试题代码:
try-catch-finally中,如果catch中return了,finally会执行吗:finally中的代码会执行。
public static void main(String[] args) {
System.out.println(test1());//执行完finally里的打印,返回test1里的值
}
public static int test1() {
//在try块中return,有可能执行不到return遇到异常就进入catch了,catch没有return最终是没有返回值,所以要给一个返回值
try {
return 1;
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("zzzzz");
}
return 0;
}
try-catch-finally中,都有return代码,以谁的为最终返回值:finally
public static void main(String[] args) {
System.out.println(test1());//return 2
}
public static int test1() {
try {
return 1;
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("zzzzz");
return 2;
}
在没有异常的情况下,对变量进行改变:
System.out.println(test1());//return 1
//因为int是基本数据类型,在返回的时候x的内容就是1,把1准备好了return,finally把x改为2,不影响已经准备好return的1
int x=1,在return的时候有一个返回值,临时变量用t接收,t=x,将1作为返回值备份了,无论finally怎么改变x的值,之前备份过了,不会改变备份的x的值。
}
public static int test1() {
int x = 0;
try {
x = 1;
return x;
} catch (Exception e) {
e.printStackTrace();
} finally {
x = 2;
}
return x;
}
在没有异常的情况下,对对象进行改变:
System.out.println(test1().getAge());// 2
//引用数据类型准备返回的是堆内存的地址。
//new一个对象,在return的时候有一个返回值,临时变量用t接收,t=s,则s,t都指向了同一个内存地址。
//当finally怎么改变s.age的值,之前备份过的是内存地址,则会改变
}
public static Student test1() {
Student s = new Student();
try {
s.age = 1;
return s;
} catch (Exception e) {
e.printStackTrace();
} finally {
s.age = 2;
}
return s;
}
static class Student {
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
面试题:
1.try catch finally能省略哪些:finally块可以省略,catch也可以省略,但是try catch组合没有意义。catch和finally可以省略其中一个。
2.try-catch-finally中,如果catch中return了,finally会执行吗:finally中的代码会执行。
3.try-catch-finally中,都有return代码,以谁的为最终返回值:finally。
4.如果try或者catch通过System.exit(0)退出程序,finally还会执行吗:不执行,退出jvm虚拟机了不会执行finally块。
5.写出5个常见的异常类型:ArrayIndexOutOfBoundsException(数组下标越界异常),ArithmeticException(算数异常),NullPointerException(空指针异常)
自定义异常:
//如果想要异常在编写代码时就报错继承Exception
//如果想要异常在运行时出错提示就继承RuntimeException
public class AgeExption extends Exception {
public AgeExption() {
this("年龄异常");
}
public AgeExption(String message) {
super(message);
}
}
/**
*
* @param age
* @throws AgeExption 年龄异常不能小于0大于190
*/
public void setAge(int age) throws AgeExption {
if (age < 0 || age > 190) {
AgeExption ageExption = new AgeExption();
throw ageExption;
}
this.age = age;
}