在异常初识中只是简单的介绍了异常的体系和异常的解决方法,这篇文章将对异常的一些特殊情况进行介绍。
1.自己定义一个异常类进行声明或者捕获
当我们不了解异常的种类或者异常中没有我们想要的类那么可以自己定义一个异常类,但是这个异常类要根据是编译时异常还是运行时异常去继承不同的异常类,当然可以直接继承最终的异常类或是包括最大的异常类。一般而言都是运行时异常,而运行时异常要继承的类为RuntimeException类。
public class Main1 {
public static void main(String[] args) {
byte[] b;
try{
b=new byte[Integer.MAX_VALUE]; //这里会产生异常,原因是数组的空间也有限制,Integer.MAX_VALUE这个值超过了数组的空间
}catch(OutOfMemoryError e){ //这是异常体系中存在的异常类,也是数组空间过大产生的异常,在这里捕获
System.out.println("数组解决了!"); //一旦捕获到这个异常就解决
b=new byte[10];
}
System.out.println(b.length);
try{
test(121);
}catch(TimeBigerExcetion e){ //这是自己定义的异常类(该类在下面)
System.out.println(e+" 该问题已处理!"); //当我们在运行时捕获到TimeBigerExcetion这个异常时,打印这个异常的信息,然后解决这个问题
}catch(TimeSmallerException e){ //当我们在运行时捕获到TimeSmallerException 这个异常时,打印这个异常的信息,然后解决这个问题
System.out.println(e+" 都已交卷,问题已处理!");
}
System.out.println("over");
}
public static void test(int time) throws TimeBigerExcetion,TimeSmallerException { //这是上面试着运行的方法,我们发现可以抛出多个异常
if(time<0){ //当传进来的参数也就是时间小于0,会产生TimeSmallerException这个异常,我们声明它的对象,并给出信息
throw new TimeSmallerException("时间小于0,不能交卷!");
}
if(time>120){ //当传进来的参数也就是时间大于正常时间,会产生TimeBigerExcetion这个异常,我们声明它的对象,并给出信息
throw new TimeBigerExcetion("时间到了,停止作答");
}
}
}
class TimeSmallerException extends RuntimeException{ //这是自己定义的一个异常类,它继承了RuntimeException类
public TimeSmallerException(String s){ //代参的构造方法,上面声明时创建的对象就是调用的该构造方法
super(s);调用父类的构造方法,将打印信息传给父类的构造方法
}
}
class TimeBigerExcetion extends Exception{//这也是自己定义的一个异常类,它继承了Exception类
public TimeBigerExcetion(String s){
super(s);
}
}
2.父类声明异常和子类声明异常之间的关系
在继承体系中,如果父类函数没有声明异常(编译时),则子类重写的函数也不可以声明异常(编译时);如果父类函数声明异常,则子类重写的函数可以声明父类异常的子类或子集。
import java.io.FileNotFoundException;
public class Main {
public static void main(String[] args) {
Zi zi=new Zi();
// zi.show();
zi.test();
}
}
class Fu{ //父类
public void show(){ //父类的show方法没有声明异常
System.out.println("Fu show...");
}
public void test() throws MuException,FuException{ //父类的test方法声明了两个异常
System.out.println("Fu test...");
}
}
class Zi extends Fu{ //子类继承父类
/*public void show() throws MuException { //这里子类重写了父类的show方法并声明了异常
//然而这里会编译报错的原因是
//Exception MuException is not compatible with throws clause in Fu.show()
//异常MuException与父类中的show方法的throw子句不兼容,
//意思就是父类在这个方法上都没有声明异常,你子类声明干啥?还不兼容。
//所以父类的方法没有声明异常,子类重写的方法也不能声明异常
System.out.println("Zi show...");
}*/
@Override
public void test(){ //子类重写父类的test方法,没有声明异常,编译没有报错。
//原因是子类继承了父类,重写了父类的方法,父类如果声明了异常
//子类重写的这个方法可以声明它的子类或者子集,下面有两个子类BoyException,GirlException,
//此方法在这里可以声明,或者也可以声明MuException或者FuException,或者都可以声明。
System.out.println("Zi test...");
}
}
class MuException extends Exception{
}
class FuException extends Exception{
}
class BoyException extends FuException{
}
class GirlException extends MuException{
}
3.finally语句块
前面介绍到,想要处理一个异常可以选择用try—catch的方法,但如果在try—catch中也出现了错误或者异常,还是会影响到程序的运行,在这里可以使用finally语句块,在此语句块中的代码,不论异常的是否发生,都会被执行。如下:
public class Main3 {
public static void main(String[] args) {
int[] a=new int[5];
try{
System.out.println(10/0); //这三句代码都会出现异常
System.out.println(a[10]);
System.out.println("over1");
}catch(Exception e){ //进行捕获处理
throw e; //捕获到这个异常后还是向上声明
}finally{ //finally语句块后面的代码仍会执行
System.out.println("finally...");
}
System.out.println("over2");
}
}
通过结果发现,虽然try-catch只捕获到了一个异常,并且向上声明,后面两句有问题的代码语句并没有捕获到,虽然程序是因异常而停止,但是在finally语句块里面的代码仍正常执行。
final finally finalize的区别区别
final修饰的变量表示变量所存储的地址不可更改
final修饰的函数表示该函数不能被重写
final修饰的类表示该类不能被继承
finally是异常处理语句中的一员,表示无论异常是否发生都会执行的语句
finalize() 当对象被回收时,由GC去调用该对象的这个函数,处理运行完的对象
public class Main {
public static void main(String[] args) {
Person p=new Person(1);
p=new Person(2);
p=new Person(3);
p=new Person(4);
p=new Person(5);
p=new Person(6);
p=new Person(7);
System.gc();
p=new Person(8);
p=new Person(9);
p=new Person(10);
}
}
class Person{
int age;
public Person(int age){
this.age=age;
}
@Override
protected void finalize() throws Throwable { //重写finalize()函数
System.out.println("拜拜!"+age);
}
}
结果不唯一,因为这是内部调用的,在外部重写并调用意义不大。
总结:异常体系中最终父类是Throwable:但凡是一个问题产生,这个问题肯定要抛出
异常肯定是从函数内部产生的,从函数内向外抛出一个问题
Error:是由JVM直接抛出的严重性问题
Exception:是指一般性的问题
RuntimeException:运行时异常,只有在程序执行时才发生的异常
Exception及其子类:编译时异常,在编译的时候就可以检测出来可能会发生异常
如何处理编译时异常?
捕获异常:try-catch
声明异常:throws
什么时候捕获?—— 如果函数内部能够解决这个问题则捕获
什么时候声明?—— 函数内部解决不了,就要向调用者提示且声明。如果抛出的异常一直被声明直到JVM都没人解决,那么直接报错
运行时异常可不可以被捕获或声明?—— 可以,但是必要,看具体需求
在捕获异常时,没有必要将大段的代码放入try语句中?—— 只需要将可能出现问题的代码放入即可,否则会导致一些和异常不相关的代码被跳过
如果不想针对性的处理异常时,可以捕获Exception即可,Throwable也可以,但是范围太大,Error就根本不需要捕获,下面用一个例子来说明何时捕获何时声明:
/*
* 张老师用电脑上课
* 电脑 蓝屏
* 电脑 冒烟
* 课程 继续/停止
* */
public class Main4 {
public static void main(String[] args) {
Teacher t=new Teacher("张"); //老师对象
try {
t.classBegin(); //先开始上课,打开电脑
} catch (ClassStopException e) { //如果这里捕获到了课程无法继续的异常
//说明电脑冒烟了,老师无法解决,课程只能停止进行,进行自习或者放学等操作
System.out.println(e.toString());
System.out.println("下课!自习!放学!....");
}
}
}
class Teacher{ //老师类
String name; //老师有其姓名的称呼
Computer com; //每个老师会有一个电脑
public Teacher(String name){
this.name=name;
this.com=new Computer();
}
public void classBegin() throws ClassStopException{
//开始上课,可能会因为电脑的问题而导致课程无法进行,所以一旦出现突发状况,课程会停止,首先声明一个课程停止的异常
try {
com.start(); //先将电脑打开,试着讲课
} catch (BlueScreenException e) { //在讲课的过程中电脑可能会出现蓝屏的状况
System.err.println(e.getMessage()); //打印出错的异常信息
com.restart(); //出现蓝屏,人为可以解决,进行电脑的重启
}catch (MaoYanException e) { //也可能出现冒烟的情况
System.out.println(e.toString());
//电脑冒烟而导致的问题异常并不是冒烟异常,而是因为电脑冒烟,人为无法处理而导致了课程无法继续进行的异常
//异常转换 就是由一个问题从而引发出的另一个问题(上层所关注)
throw new ClassStopException("课程无法继续....");
//所以一旦电脑出现冒烟问题,老师无法解决,这里不能try—catch进行捕获处理,只能向上声明让别人来处理
}
System.out.println(name+"老师上课..."); //如果没有任何问题,那么课程继续
}
}
class Computer{ //电脑类
int state=2; //状态标志
public void start() throws BlueScreenException, MaoYanException{ //电脑开机可能出现异常
System.out.println("电脑开机...");
if(state==1){ //如果状态标志发生变化,相应的电脑状态出现
//电脑出现问题并不是电脑自己重启或者自己修理好的,而是它出现问题反馈给使用者,
//让使用者去解决相应的问题,所有这里一旦出现状况应该是声明
throw new BlueScreenException("电脑蓝屏了....");
}else if(state==2){
throw new MaoYanException("冒烟了....");
}
}
public void restart(){ //重启函数
System.out.println("电脑重启...");
}
}
//蓝屏异常
class BlueScreenException extends Exception{
public BlueScreenException(String info){
super(info);
}
}
//冒烟异常
class MaoYanException extends Exception{
public MaoYanException(String info){
super(info);
}
}
//课程无法继续异常
class ClassStopException extends Exception{
public ClassStopException(String info){
super(info);
}
}