这部分的笔记几乎是没做任何整理,直接把课上的笔记和教材照搬进来,可做的练习也很少。只要会try…catch方法,明白异常和异常抛出是个怎么回事就行…
在java程序,出现了不正常或错误的情况,称为异常
异常就是一个对象,描述一些不正常的情况信息:异常的原因,位置,类型
异常也是一种处理机制,我们可以对异常进行捕获处理,或者结束程序
出现了错误,必须修改源代码,出现了异常,可以捕获
Throwable: 可以抛出,是异常体系的顶层父类,其他的错误或异常,都是他的子类,只有Throwable体系下的类,才可以使用异常的处理机制来处理
Error:错误,用于描述那些无法捕获和处理的错误信息
Exception:异常,用于描述那些可以捕获和处理的错误信息
RuntimeException:运行时异常,这种异常在编译的时候不会检测,能够正常通过,只有出现相对应的问题的时候,才会被抛出
编译时异常:除了RuntimeException之外都是编译异常,编译时有异常编译就不能通过,必须要对编译异常进行处理
如果出现了不正常的情况,jvm就把其封装为异常对象,同时再抛出,抛出给代码的调用者
方法执行的时候,如果其他方法产生了异常,在执行的时如果没有手动处理,就会把这个问题抛给方法的调用者,调用者也没处理的话jvm就把这个异常抛出,用红色信息显示
总结:jvm默认处理的方式:一层层向上抛出,最后到达jvm,jvm将异常信息打印出来,同时结束程序
目的:就是为了当程序出现问题,也能让程序继续执行下去,不至于立即结束程序
手动处理异常的分类:
(1) 异常的声明式处理
(2) 异常的捕获式处理
(1) try…catch
(2) try…catch…finally
(3) try… finally(此方式不能捕获异常)
格式:
try{
可能出现问题的代码
}catch( 异常的类型 变量名){
处理异常的代码
}
try:尝试执行try后大括号中的代码
catch :如果try后的大括号中有问题产生,就可通过catch捕获
小括号中声明可能出现的异常类型,变量名,就是一个引用,指向了将来出现的异常对象
执行流程:
先执行try后的大括号中的代码,如没问题,就跳过trycatch语句,继续执行后面的代码
如果产生了问题,就用catch进行异常的捕获,并把异常对象赋值给变量名,catch中写上异常的处理方式,方式:记录日志,打印错误信息,或者重新执行try后的代码最简单的方式,鸵鸟政策,或者自己将异常抛出
catch后的代码块如果执行完,就可以执行catch大括号后的代码
如果发现了catch没有声明的异常,则无法捕获异常,该异常就使用jvm默认的方式来处理
package Test;
public class Test {
public static void main(String[] args) {
String s = null; //空指针异常,是异常就可以进行
try {//可能发生问题的代码
System.out.println(s.length());
} catch (Exception e) {//出现了能够捕获的异常
System.out.println("空指针异常了");
}
System.out.println("我还能继续进行");
}
}
可能出现多个异常,需要准备多种处理方式,准备多个catch块
格式
try{
可能出现异常的代码
}catch(异常类型1 变量名1){
异常处理方式1
}catch(异常类型2 变量名2){
异常的处理方式2
}catch(异常类型3 变量名3){
异常的处理方式3
}
执行流程
如果try后的代码没问题,就直接结束整个catch块
如果出现了问题 jvm把问题封装为一个异常对象,查看这个异常度下行的类型,哪个catch后的异常类型和该类型一致,就执行哪个异常处理方式,执行完就 结束整个catch块,继续执行其他代码
注意:
jdk1.7新的捕获异常处理方式
try{
有问题的代码
}catch(异常类型1 | 异常类型2 | 异常类型3 |… 变量名){
多种异常处理方式是一样的
}
package Test;
public class Test {
public static void main(String[] args) {
int[] arr = {1,2,3};
arr = null;
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException | NullPointerException e) {
//此时两个异常共用一个处理方式
System.out.println("傻子你咋操作的数组");
}
System.out.println("~~~~~~~~~~~~");
test();
}
private static void test() {
int[] arr = {1,2,3};
//arr = null;
try {
System.out.println(arr[10]);
}catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组索引越界,请检查下标");
} catch (NullPointerException e) {
System.out.println("你操作的数组为null,请给对象赋值");
} catch (RuntimeException e) {//大范围的异常一定要放在小范围的异常下面
// TODO: handle exception
}
System.out.println("我总能执行");
}
}
格式
try{
可能出现问题的代码
}catch(异常类型 变量名){
异常的处理方式
}finally{
一定会执行的代码
}
finally :最终的,一定会执行的代码
执行流程:
try后的代码如果没有问题,就执行finally中的内容
如果有问题先执行catch,再执行finally
无论有没有异常出现,都会执行finally的代码块
用途:释放资源
package Test;
public class Test {
public static void main(String[] args) {
int[] arr = {1,2,3};
try {
System.out.println(arr[2]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("索引越界了");
} finally {
System.out.println("一定会执行");
}
System.out.println("异常处理后,也能执行");
}
}
try{
可能出现问题的代码
}finally{
一定要执行的代码
}
执行流程:
无法捕获异常
try后如果没有问题,就会执行finally,程序继续执行后面的内容
try后如果有问题,也会执行finally,执行之后程序停止
package Test;
public class Test {
public static void main(String[] args) {
String s = "abc";
try {
s.substring(1,4);
}finally {
System.out.println("一定要执行的代码");
}
System.out.println("我可能会执行");
}
}
相同点:无论是编译时异常还是运行时异常,都是运行代码的阶段才可能发生
区别:
(1) 继承体系
运行时异常都继承自:RuntimeException
编译时异常都继承自:Exception下除了RuntimeException之外
(2) 是否要处理的区别
运行时异常,可以选择处理,也可以不处理
编译时异常,如果产生编译时异常,必须要进行处理,否则程序无法运行
除了Throwable下定义的方法,子类都没有什么特殊的方法,所以只需要研究Throwable中的方法
构造方法:
(1) Throwable()
(2) Throwable(String message) 指定异常信息的构造方法
(3) Throwable(Throwable cause) 创建异常原因对象的构造方法
常用方法:
(1) getCause():获取异常原因对象,有的话返回cause 没有返回null
(2) getMessage: 获取异常信息
(3) toString() 把异常对象转为字符串
(4) printStackTrace(): 打印产出异常的轨迹
package Test;
public class Test {
public static void main(String[] args) {
int[] ages = {18,29,22};
try {
System.out.println(ages[10]);
} catch (Exception e) {
String message = e.getMessage();
System.out.println(message);//获取异常信息
System.out.println(e.toString());//把异常对象转为字符串
System.out.println(e.getCause());//获取异常原因对象
e.printStackTrace();//打印异常轨迹
}
}
}
作用:把异常对象给抛出
异常是一个独享,当程序执行的时候,发生了问题,就可将异常情况给抛出,抛给调用者,想要解决扔这个问题,就需要使用throw关键字
作用:创建一个异常对象,使用throw抛出,实现程序结束或者跳转
throw抛出异常分类
(1) 如果抛出的是运行时异常,那么可以选择处理,也可以不处理,相当于没有异常一样
(2) 如果抛出的是编译时异常,必须对类型的异常进行处理,否则无法编译通过
抛出:用于声明一个异常类型
在某个方法中,如果有一些编译时异常,要被抛出,方法内部不想处理,就可通过关键字throws把这个异常声明在方法的后面
声明的好处:
声明异常的格式
修饰 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2 …{
可能有异常的代码
}
声明异常的分类:
(1) 如果声明的是一个运行时异常,那么声明不生命没有任何区别,所以没有必要声明运行时异常
(2) 如果声明的是一个编译时异常,那么在一个方法调用含有编译时异常的方法,必须对带有声明异常的方法进行处理,处理的方式,捕获式处理和 声明式处理
注意事项
throw用于抛出一个异常对象,throws声明一个异常类型
throw是对象实实在在抛出了,一旦使用了throw就一定有一个对象抛出,throws是对可能出现异常的类型的声明,声明了一个异常类型,在这个方法中,也可以不出现任何一场
throw出现在方法中,throws出现在方法参数后的小括号后
jdk提供了很多异常类型,但是大多数没有自己的特有的方法
如果有了很多异常类型的名字,将来在不同的异常情况下,就可以使用不同的异常类型去创建对象,可以通过类名去区分到底出现了什么异常
在自己的业务中,jdk提供的各种情况,都无法描述当前的情况,就需要自己定义异常类型,用于自己的项目中
自定义异常的步骤
(1) 定义一个类,以Exception结尾,例如 AgeException,表示一个非法年龄异常
(2) 让自己定义的类去继承一个Exception或者RuntimeException
如果定义的是编译时异常,就是Exception
如果是运行时异常,就使用RuntimeException
构造方法需要手动添加的
package Test;
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.setAge(-18);
}
}
class Student{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
AgeException a = new AgeException("年龄非法");
if(age < 0) {
throw a;
}
this.age = age;
}
@Override
public String toString() {
return "Stundent [name=" + name + ", age=" + age + "]";
}
}
class AgeException extends RuntimeException{
public AgeException() {
super();
// TODO Auto-generated constructor stub
}
public AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public AgeException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public AgeException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public AgeException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}