一、异常的定义
Java中的异常:
1、错误(Error):是指JVM系统内部错误、资源耗尽等严重情况。程序员对此错误一般无能为力。
2、例外(Exception):则是指因编程错误或偶然的外在因素导致的一般性问题,程序员是可以进行处理的。
注意!
一般我们在Java中所说的异常,其实指代的就是“例外”。
二、异常层级结构
图示结构:
|----Object类
|-------- Throwable 类(所有的Error 和 Exception的父类)
|--------Error类(描述错误的,程序员是无能为力的)
|--------Exception类(描述的是例外,程序员是可以进行处理的)【研究的重点】
|----------- RuntimeException(运行时异常)【只有在程序执行起来后才会暴露出来的异常】
还有一部分异常属于“检查性”异常,在编码的时候就会主动的提示进行处理
三、常见异常
3.1、运行时异常
常见几种异常(运行时异常):
-
类型转化异常 ClassCastException
-
空指针异常 NullPointerException
-
数字格式化异常 NumberFormatException
以上这几种异常,都是在程序运行的过程中,才会引发的异常;
3.2、检查性异常
package com.exception.demo;
public class Car {
private Car() {
}
public Car(String name) {
}
}
package com.exception.demo;
public class Car_Test {
public static void main(String[] args) {
try {
//动态加载一个指定的类
Class carClas = Class.forName("com.it.www.exceptiontest.Car");
//通过类结构,调用无参数的构造方法创建对象;
Object obj = carClas.newInstance();
} catch (ClassNotFoundException e) {//包名或者是类名写错了,无法找到这个类;
e.printStackTrace();
} catch (InstantiationException e) { //没有相对应的构造方法,则会抛出这个异常;
e.printStackTrace();
} catch (IllegalAccessException e) { //构造存在,但是访问权限不够;
e.printStackTrace();
}
}
}
常见几种异常(检查性异常):
-
实例化异常 InstantiationException
-
不规则访问 IllegalAccessException
-
类不能找到 ClassNotFoundException
以上这几种异常,都是属于检查性异常,在编写代码的过程中开发工具会进行主动的提示,必须要处理;
四、异常的处理
4.1、try-catch方式处理异常
在Java语言中,针对运行时异常,我们推荐不进行处理,针对检查性异常必须要进行处理的,那么如何来处理这些检查性异常呢?
异常处理的语法格式:
try{
//可能会产生异常的Java程序代码;
}catch(异常类型 e){
//产生对应的异常需要执行的代码部分;
}catch(异常类型 e){
//产生对应的异常需要执行的代码部分;
}.......
finally{
//不管是否产生异常,都会被执行的部分,主要用于资源的释放;
}
执行流程
- 程序从 try 里面的代码开始执行
- 出现异常,就会跳转到对应的 catch 里面去执行
- 执行完毕之后,程序还可以继续往下执行
检查性异常和运行时异常的区别
检查性异常
都是Exception类及其子类
必须显示处理,否则程序就会发生错误,无法通过编译
运行时异常
都是RuntimeException类及其子类
无需显示处理,也可以和编译时异常一样处理
针对检查性异常,必须要手动进行处理:
package com.exception.demo;
public class Car_Test {
public static void main(String[] args) {
try {
// 动态加载一个指定的类
Class carClas = Class.forName("om.exception.demo.Car");
// 通过类结构,调用无参数的构造方法创建对象;
Object obj = carClas.newInstance();
} catch (ClassNotFoundException e) {// 包名或者是类名写错了,无法找到这个类;
e.printStackTrace();
} catch (InstantiationException e) { // 没有相对应的构造方法,则会抛出这个异常;
e.printStackTrace();
} catch (IllegalAccessException e) { // 构造存在,但是访问权限不够;
e.printStackTrace();
}
}
}
注意!
1、finally表示不管是否会产生异常,都会被执行的部分,这主要是用于进行资源的释放,当然从语法的角度是可以省略的;
2、被监测的代码如果产生多种类型的异常,就会对应的产生多个catch的部分,在多个catch部分的顺序是有要求的,我们不能将父类前置到子类的前面;
try { // 动态加载一个指定的类 Class carClas = Class.forName("om.exception.demo.Car"); // 通过类结构,调用无参数的构造方法创建对象; Object obj = carClas.newInstance(); } catch (Exception e) {// 包名或者是类名写错了,无法找到这个类; e.printStackTrace(); } catch (InstantiationException e) { // 没有相对应的构造方法,则会抛出这个异常; e.printStackTrace(); } catch (IllegalAccessException e) { // 构造存在,但是访问权限不够; e.printStackTrace(); }
3、针对return与finally配合使用,首先会执行finally,然后在继续返回
4.2、Throwable成员方法
方法名 | 说明 |
---|---|
public String getMessage() | 返回此 throwable 的详细消息字符串 |
public String toString() | 返回此可抛出的简短描述 |
public void printStackTrace() | 把异常的错误信息输出在控制台 |
package com.exception.demo;
public class ThrowableDemo {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]); // new ArrayIndexOutOfBoundsException();
System.out.println("这里能够访问到吗");
} catch (ArrayIndexOutOfBoundsException e) { // new ArrayIndexOutOfBoundsException();
// e.printStackTrace();
// public String getMessage():返回此 throwable 的详细消息字符串
// System.out.println(e.getMessage());
// Index 3 out of bounds for length 3
// public String toString():返回此可抛出的简短描述
// System.out.println(e.toString());
// java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
// public void printStackTrace():把异常的错误信息输出在控制台
e.printStackTrace();
// java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
// at com.itheima_02.ExceptionDemo02.method(ExceptionDemo02.java:18)
// at com.itheima_02.ExceptionDemo02.main(ExceptionDemo02.java:11)
}
}
}
4.3、throws 和 throw的使用
4.3.1、throws 使用
定义格式
public void 方法() throws 异常类名 {
}
代码:
package com.exception.demo;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("开始");
// method();
try {
method2();
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("结束");
}
// 检查性异常
public static void method2() throws ParseException {
String s = "2048-08-09";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s);
System.out.println(d);
}
// 运行时异常
public static void method() throws ArrayIndexOutOfBoundsException {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
}
}
注意事项
- 这个throws格式是跟在方法的括号后面的
- 检查性异常必须要进行处理,两种处理方案:try…catch …或者 throws,如果采用 throws 这种方案,将来谁调用谁处理
- 运行时异常可以不处理,出现问题后,需要我们回来修改代码
4.3.1、throw 使用
异常的抛出
可以将产生的异常进行继续向外抛出,让调用者进行捕获和处理。
package com.exception.demo;
public class ExceptionDemo02 {
public static void main(String[] args) {
ExceptionDemo02 demo = new ExceptionDemo02();
// 调用者----全然不知method1方法中的所有的异常;
demo.method1();
// 调用者----针对使用了throws进行对外声明的操作,那么我们在调用的时候,就不能视而不见,必须要进行手动处理;
try {
demo.method2();
} catch (ClassNotFoundException e) {
// 设置自己的处理方式;
e.printStackTrace();
}
try {
demo.method3();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
// 第一种形式:在method1方法内部,我们针对异常进行了内部处理。
public void method1() {
try {
Class personClas = Class.forName("com.it.www.exceptionapp.Person");
Object obj = personClas.newInstance();
System.out.println(obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
// 第二种形式:在method2方法内部,我们针对异常进行了内部处理,但是同时我们又将异常进行了抛出.
// 这时,我们需要在产生异常的位置,通过throw关键字进行继续抛出的声明,并且以方法为单位使用throws对外进行声明。
public void method2() throws ClassNotFoundException {
try {
Class personClas = Class.forName("com.it.www.exceptionapp.Person");
Object obj = personClas.newInstance();
System.out.println(obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw e; // 将ClassNotFoundException继续向外抛出;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
// 第三种形式:在method3方法内部我们不会进行任何的处理,全部通过throws统一对外进行声明,哪里调用,就在哪里进行处理;
public void method3() throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
Class personClas = Class.forName("com.it.www.exceptionapp.Person");
Object obj = personClas.newInstance();
}
}
说明:
以后在开发的过程中,如果我们编写的代码是大量作为工具的形式被大家使用,那么针对内部的异常可以直接使用throws关键字对外做声明,谁使用谁处理。
如果是自己编写的功能业务,比较独立或者是不经常进行共用,那么我们可以在自己的内部进行处理。
4.3.3、throws和throw的区别
五、自定义异常
虽然Java内部提供了非常丰富的异常处理机制,还是满足不了我们开发的需求,比如:我们针对年龄进行限制,这时我们就需要掌握自定义异常的处理方式:我们模仿Java内部定义各种异常类的模式,推出我们自己针对某个模块或者是某个业务来编写自己的异常类;
package com.exception.demo;
import java.util.Scanner;
class ScoreException extends Exception {
public ScoreException() {
}
public ScoreException(String message) {
super(message);
}
}
public class CustomExceptions {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入分数:");
int score = sc.nextInt();
Teacher t = new Teacher();
try {
t.checkScore(score);
} catch (ScoreException e) {
e.printStackTrace();
}
}
}
class Teacher {
public void checkScore(int score) throws ScoreException {
if (score < 0 || score > 100) {
// throw new ScoreException();
throw new ScoreException("你给的分数有误,分数应该在0-100之间");
} else {
System.out.println("成绩正常");
}
}
}
提示!
自定义异常类就需要借助于Java内部的异常类(可以是Exception 、 也可以使用RuntimeException)。