目录
目录
1、异常
什么是异常?
- Java代码在运行时期发生的问题就是异常
- 异常类:在Java中,把异常信息封装成了一个类,当出现了问题时,就会胡藏剑异常对象,并抛出异常相关的信息(如异常出现的位置、原因等)
- 比如:ArrayIndedOutOfBoundsException
2、异常的继承体系
- 在Java中,使用Exception类来描述异常。通过查询API,发现Exception其实时Throwable的子类。Throwable是Java语言中所有错误或异常的父类。
- RuntimeException及其子类、只能在java程序运行中出现
- Error是Throwable的子类,它与Exception平级,它用来表示Java程序中可能会产生的严重错误。解决办法只有一个,就是修改代码避免Error的产生。
Throwable :所有错误与异常的超类
|--Error 错误
|--Exception 编译期异常,进行编译java程序时出现的问题
|--RuntimeException 运行期异常,java程序运行过程中出现的问题
3、异常与错误的区别
- 异常:表示程序在编译、运行期间发生的某种异常(XXXException),我们可以对异常进行具体的处理。若不处理异常,程序将结束运行。
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr[3]);
// 该句运行时,发生了ArrayIndexOutOfBoundsException,
// 由于没有处理异常,导致程序无法运行,程序结束
}
- 错误:指程序在运行期间发生了某种错误(XxxError),Error错误通常没有具体的处理方式,程序将会结束运行。Error错误的发生往往都是系统级别的问题,我们无法针对处理,只能修改代码。
public static void main(String[] args) {
int[] arr = new int[100 * 1024 * 1024];
// 该句运行时会发生内存溢出错误OutOfMemoryError,由于开辟了过大的数组空间
//导致JVM在分配数组空间时超过了JVM内存空间,直接发生错误
}
4、异常对象的产生原因及处理方式
class ArrayTools{
public static int getElement (int[] arr,int index) {
int element = arr[index];
return element;
}
public class ExceptionDemo{
public static void main(String[] args) {
int[] arr = {1,2,3};
int element = ArrayTools.getElement(arr,4);
System.out.println("element="+element);
}
}
原因分析:
- 由于没有找到索引【4】,导致运行时发生了异常,这个异常JVM认识:ArrayIndexOutOfBoundsException。这个异常Java本省有描述:异常的名称、异常的内容、异常产生的位置。 Java将这些信息直接封装到异常对象中:new ArrayIndexOutOfBoundsException(4);
- throw new ArrayIndexOutOfBoundsException(4) 产生异常对象,JVM将产生的异常抛给调用者main()方法。
- main()方法接收到了数组索引越界异常对象。由于main()方法并没有进入处理异常,main()方法会继续把异常抛给调用者JVM,当JVM接收到异常后,将异常的名称、异常的内容、异常产生的位置都显示在控制台上,同时让程序立刻终止。
异常的处理方式:
- JVM的默认处理方式 将异常对象的名称、原因、位置等信息输出到控制台,同时结束程序。一旦有异常发生,其后面的代码不再执行
- 解决程序中异常的手动方式
- 编写处理代码:try...catch...finally
- 抛出throws.
5、抛出异常thorw
在java中,提供了一个throw关键字,用来抛出一个指定的异常对象。
- 什么时候使用throw关键字? ——当调用方法使用接受到的参数时,首先需要对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。
- 使用throw关键字具体操作
- 创建一个异常对象,封装一些提示信息(信息可以自己编写)
- 通过关键字throw将这个异常对象告知给调用者。
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
使用格式:
throw new 异常类名(参数);
throw new NullPointerException("要访问的数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
public class ArrayTools {
public static int getElement(int arr[],int index){
if(arr==null){
throw new NullPointerException("要访问的数组不存在");
}
if(index < 0 || index >= arr.length){
throw new ArrayIndexOutOfBoundsException("该索引"+index+"在数组中不不存在");
}
int element = arr[index];
return element;
}
}
public class ExceptionDemo {
public static void main(String[] args) {
int[] arr = {1,2,3};
int element = ArrayTools.getElement(arr,4);
System.out.println("element="+element);
}
}
6、声明异常throws
声明:将问题表示出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获异常,那么必须通过throws进行声明,让调用者去处理
声明格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2..{}
注意事项:
throws用于进行异常类的声明,若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开。
public void show(int x) throws Exception {
if(x>0){
throw new Exception() ;
}else {
System.out.println("x="+x);
}
}
7、 捕获异常 try ..catch...finally
捕获:java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理
捕获异常格式:
try{
// 需要被检测的语句
}catch (异常类 变量){
// 异常的处理语句
}finally {
// 一定会被执行的语句
}
- try:该代码块中编写可能产生异常的代码
- catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理
- finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句不能执行,而finally就是解决这个问题的。在finally代码块中的代码都是一定会被执行的!
- try...catch... 处理掉异常后,程序可以继续执行
public static void main(String[] args) {
int[] arr = new int[3];
try {
System.out.println(arr[4]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("异常发生了..");
}finally {
arr = null; // 把arr数组指向null,通过垃圾回收器,进行内存垃圾的清除
}
System.out.println(arr);
System.out.println("程序结束运行!");
}
}
8、异常处理的组合方式
- try..catch..finally:检测异常,并传递给catch处理,最后在fianlly中进行资源释放。
- try..catch 组合:对代码进行异常检测,并对检测到的异常传递给catch处理。
- try..finally 组合:对代码进行异常检测,由于没有catch,一般会被默认的JVM输出。异常没有捕获处理,但是功能所开启的资源需要进行关闭,所以finally的存在是关闭资源。
- 一个try多个catch组合:对代码快进行异常检测,并对检测到的异常传递给catch处理。对每种异常信息进行不同的捕获处理。
void show() {
try{
throw new Exception();
}catch(XxxException e){
// 处理方式
}catch(YyyException e){
// 处理方式
}catch(ZzzException e){
// 处理方式
}
}
注意事项:
这种异常处理方式,要求多个catch中的异常不能相同。
多个catch处理的细节:
多个catch小括号中,写的是异常类的类名,它是由顺序关系的
- 平级异常——抛出的异常类之间,没有继承关系,没有顺序
NullPointerException extends RuntimeException
NoSuchException extends RuntimeException
ArrayIndexOutOfBoundsException extends RuntimeException
- 上下级关系的异常 ——越高级的父类,写在越下面
NullPointerException extends RuntimeException extends Exception
try {
throw new Exception();
}catch(NullPointerException e){
}catch(RuntimeException e){
}catch(Exception e){
}
9、finally代码块
特点:被finally控制的语句体一定会执行
作用:无论程序是否有异常出现,程序必须执行释放资源。如:IO流操作、数据库操作。
10、调用抛出异常方法
有 try...catch 和 throws 两种
在实际开发中使用哪种异常处理方式?
- 能自己处理的尽量自己处理。(建议使用 try...catch)
11、运行期异常
1、概述:
- RuntimeException和它的所有子类异常,都属于运行期异常 如
- ArrayIndexOutOfBoundsException,NullPointerException 等都属于运行时期异常
2、特点:
- 方法中抛出运行时期异常,方法定义中无需throws声明,调用者也无需处理此异常。
- 运行时期异常一旦发生,需要程序人员修改源代码。
- 设计原因:运行异常,不能发生,但如果发生了,程序人员要停止程序,修改源代码。运行异常一旦发生,后面的代码没有执行的意义。
12、方法重写时异常的处理
- 子类覆盖父类方法时,如果父类的方法声明异常,子类只能声明父类异常或该异常的的子类,获取不声明。
class Fu{
public void method() throws RuntimeException{
}
}
class Zi extends Fu{
public void method() throws RuntimeException{} // 抛出父类一样的异常
//public void method() throws NullPointerException{} // 抛出父类异常
//public void method(){}
}
- 当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集
class Fu{
public void method() throws NullPointerException,ClassCastException{
}
}
class Zi extends Fu{
public void method() throws NullPointerException,ClassCastException{} // 抛出父类一样的异常
//public void method() throws NullPointerException {} // 抛出父类异常中的一部分
//public void method() throws ClassCastException {} // 抛出父类异常中的一部分
}
- 当覆盖的方法没有异常声明时,子类覆盖时无法声明异常
class Fu{
public void method(){}
}
class Zi extends Fu{
public void method() throws Exception{} // 错误的方式
}
- 父类或接口中,没有声明异常,但子类覆盖方法时发生了异常,怎么办?
无法进行throws声明,只能catch捕获。万一问题处理不了,catch中继续throw抛出,但是只能将异常转换为RuntimeException子类抛出。
interface Inter{
public abstract void method();
}
public class Zi implements Inter{
@Override
public void method() {
int[] arr = null;
if (arr == null){
try {
throw new Exception("数组不存在!");
}catch (Exception e){
System.out.println("父方法中没有声明异常,子类中不能抛出Exception异常");
throw new RuntimeException(e);
}
}
}
}
13、异常中常用方法
- getMessage():返回该异常的详细信息字符串,即异常提示信息
- printStackTrace(): 在控制台输出该异常的名称、详细信息字符串、异常出现的代码位置。
- toString():返回该异常的名称与详细信息字符串
public class ExceptionDemo {
public static void main(String[] args) {
try{
Demo demo = null;
if(demo == null){
throw new NullPointerException("出现空指针异常");
}
}catch (NullPointerException e){
String message = e.getMessage();
System.out.println("getMessage():"+message);
String s = e.toString();
System.out.println("toString():"+s);
System.out.println("printStackTrace():");
e.printStackTrace();
}
}
}
14、自定义异常类的定义
class 异常名 extends Exception { // 或者继承RuntimeException
public MyException(){
super();
}
public MyException(String message){
super(message);
}
}
自定义异常继承RuntimeException:
public class MyRuntimeException extends RuntimeException{
public MyRuntimeException(){
super();
}
public MyRuntimeException(String message){
super(message);
}
}
15、自定义异常的练习
定义Person类,包含name和age两个成员属性
在Person类的有参构造方法中,进行年龄范围的判读,若年龄为负数或者大于100岁,则抛出NoAgeException异常,异常提示信息:“年龄数值非法”
要求:在测试类中,调用有参构造方法,完成Person对象创建,并进行异常处理
(1)自定义异常类NoAgeException
public class NoAgeException extends Exception{
public NoAgeException(){
super();
}
public NoAgeException(String message){
super(message);
}
}
(2)自定义类Person
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) throws NoAgeException {
if(age<0 || age>200){
throw new NoAgeException(age + "年龄数值非法");
}
this.name = name;
this.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) {
this.age = age;
}
}
(3)测试类
public class NoAgeExceptionDemo {
public static void main(String[] args) {
try {
Person person = new Person("小镭", 999);
System.out.println(person.getAge());
} catch (NoAgeException e) {
e.printStackTrace();
}
}
}
构造方法抛出的这个NoAgeException到底是继承Exception,还是继承RuntimeException?
- 继承Exception,必须要throws声明,告知调用者进行捕获,一旦问题处理了,调用者程序会继续执行
- 继承RuntimeException,不需要throws声明,这时调用是不需要写捕获异常代码,因为调用者根本不知道有问题。一旦发生NoAgeException,调用者的程序会停掉,并由JVM将信息显示到屏幕,让调用者看到问题,修正代码