一、异常机制介绍
1.可以先通过一段代码来了解异常
int num1 = 10;
int num2 = 0;
int res = num1 / num2;
当执行到第三行时,程序就会出现(抛出)异常 ArithmeticException 当抛出异常后,程序就退出,崩溃了 , 下面的代码就不在执行,java中提供了异常处理机制(如果对异常进行处理,即使出现异常后面的程序也能继续执行)
try {
int res = num1 / num2;
} catch (Exception e) {
System.out.println("出现异常的原因=" + e.getMessage());//输出异常信息
}
System.out.println("程序继续运行....");
代码输出如下:
出现异常的原因=/ by zero
程序继续运行...
从这里我们可以对异常机制有个简单的了解:就是防止一些代码异常影响整个代码
二.异常体系图
1. 分析:Exception(异常)分两类runtimeexception(运行时异常)和编译异常
运行时异常主要有以下:
String name = null;
System.out.println(name.length());///抛出NullPointerException
int[] arr = {1,2,4};
for (int i = 0; i <= arr.length; i++) {
System.out.println(arr[i]);
}
public class ClassCastException_ {
public static void main(String[] args) {
A b = new B(); //向上转型
B b2 = (B)b;//向下转型,这里是 OK
C c2 = (C)b;//这里抛出 ClassCastException
}
}
class A {}
class B extends A {}
class C extends A {}
String name = "哈哈"; //将 String 转成 int
int num = Integer.parseInt(name);//抛出 NumberFormatException
三.异常处理
异常处理的方式:
1 try-catch-finally
(程序员在代码中捕捉发生的异常,自行处理)
try
捕获异常的第一步是用try{…}语句块选定捕获异常的范围, 将可能出现异常的代码放在try语句块中。在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配。 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常处理,一旦处理完成就跳出当前的try-catch结构(在没有写finally的情况下)。继续执行其后的代码。在try结构中声明的变量,出了try结构之后,就不能被调用。
catch (Exceptiontype e)
在catch语句块中是对异常对象进行处理的代码。 每个try语句块可以伴随一个或多个catch语句, 用于处理可能产生的不同类型的异常对象。catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓,如果异常类型满足子父类的关系,则要求子类一定要声明在父类的上面,否则报错。
finally
捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。
不论在try代码块中是否发生了异常事件, catch语句是否执行, catch语句是否有异常, catch语句中是否有return,finally块中的语句都会被执行。
finaly中声明的是一定会被执行的代码,即使catch中出现了异常,try中有return语句,catch中有return语句等情况。
例子:
单个异常:最开始的例子
多个异常:
public static void main(String[] args) {
try {
Person person = new Person(); //person = null;
System.out.println(person.getName());//NullPointerException
int n1 = 10;
int n2 = 0;
int res = n1 / n2;//ArithmeticException
} catch (NullPointerException e) {
System.out.println("空指针异常=" + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("算术异常=" + e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
}
finally {
}
}
}
class Person {
private String name = "jack";
public String getName() {
return name;
}
}
总结:
4)当有多个异常时,子类异常写在前面;
2.throws
(将发生的异常抛出,交给调用者处理,最顶级的处理着是JVM)
如果一个方法(中的语句执行时)可能生成某种异常, 但是并不能确定如何处理这种异常, 则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
在方法声明中用throws语句可以声明抛出异常的列表, throws后面的异常类型可以是方法中产生的异常类型, 也可以是它的父类。
一旦方法体执行时,出现异常,仍会在异常代码处,生成一个异常类的对象,此对象满足throws后异常类型是,就会被抛出。异常代码后续的代码,就不在执行。
throws的方式只是将异常抛给了方法的调用者,并没有真正将异常处理掉。
四、自定义异常
例题:当我们接受一个Person对象年龄时,要求范围在18-200之间,否则抛出一个自定义异常(要求继承RuntimeException),并给出提示信息。
public class CustomException {
public static void main(String[] args) /*throws AgeException*/ {
int age = 180; //要求范围在 18 – 120 之间,否则抛出一个自定义异常
if(!(age >= 18 && age <= 120)) {
//这里我们可以通过构造器,设置信息
throw new AgeException("年龄需要在 18~120 之间");
}
System.out.println("你的年龄范围正确.");
}
}
class AgeException extends RuntimeException {
public AgeException(String message) {
//构造器
super(message); //这里的super调用的是RuntimeException父类里的构造器 输出异常信息
}
}
//1. 一般情况下,我们自定义异常是继承 RuntimeException
如果用extends Exception (抛出编译异常)就必须在main函数 throws AgeException
//2. 即把自定义异常做成 运行时异常,好处时,我们可以使用默认的处理机制
//3. 即比较方便
到这有两个疑问:
1.throws和throw的区别。
throw是自己定义的异常,就是说 编程和运行都不会出问题,但是不符合逻辑,就像去取钱。钱被取成负数。不符合逻辑。所以要用throw。
throws是在函数声明的地方写的,表示该函数可能出现的异常,需要调用单位来处理。一般有throw的函数要配合throws使用。
上面的两种都是异常的处理方法之一“抛”,意味着函数异常没有被解决,而是交给上级解决。最终解决需要try和catch来解决
用throw抛出一个异常对象,然后用catch接受。
2.throws有什么作用?什么意义?
作用:
当你的方法里抛出了checked异常(编译异常),如你不catch,代表你当时不处理(不想处理或没条件处理),但你必须得通过"throws那个异常"告诉系统说,这儿有个问题,我现在不处理,将来一定别人要处理,否则执行到它,马克-to-win:系统会"不优雅"的崩溃。举个例子,工兵张三发现了地雷,假如他处理,完事就完事儿了。但是他发现了地雷,自己却没带齐工具,没法处理,他必须做个标记,说这儿有一个地雷,别的工兵将来一定要处理,否则将来有人踩上去会爆炸。
注意:throws只是标记,并没处理,执行到那,系统还是会崩溃!