Java 异常体系
异常:指的就是程序在编译或运行过程中出现的一些错误
万事万物皆对象,在Java语言中,异常本身也是一个对象
怎么描述出现的问题?
问题的名称,问题的描述/原因,问题发生的位置
package com.company;
public class Test {
public static void main(String[] args) {
int[] arr = new int[10];
System.out.println(arr[10]);
/*Exception in thread "main" 问题发生的位置:哪个线程
java.lang.ArrayIndexOutOfBoundsException 问题的名称
: 10 问题的描述/原因
at com.company.Test.main(Test.java:6)问题发生的未知:代码第几行
*/
}
}
但凡是问题 都要被提出/抛出 不能将问题当成一个正常的返回值来处理——解决问题的方法(声明,捕获)
异常抛出语句:throw new xxxException();
在Java中 异常体系的最终父类是Throwable 只有当对象是此类(或者其子类之一)的实例时,才能通过Java虚拟机或者Java throw语句抛出
什么叫做由Java虚拟机直接抛出,什么叫手动throw抛出?
1.由JVM直接抛出:JVM会自动检测程序 如果出现异常 则自动创建该异常对象 然后去抛出
2.手动抛出:程序员在代码中手写throw new xxxException();
Throwable有两个子类
Error:严重性问题 一般而言是由JVM直接抛出 主要是内存上的一些问题
对于内存而言 我们是不能直接控制的 我们也不是很清楚什么时候会发生内存错误 所以不会自主抛出异常
Exception:一般性的问题 可以由JVM直接抛出 或者throw抛出 例如:
编译时异常:Exception及其其他的子类异常:是那些可能在Java程序正常编译期间抛出的异常的父类 在程序编译期间就能够发现的问题
运行时异常:RuntimeException及其子类异常:那些可能在Java虚拟机正常运行期间抛出的异常的父类 在程序运行期间才能发现的异常,如果这个一旦问题发生,那么程序就直接中断
运行时异常可以声明或者捕获,一般不会声明,声明了程序依然会报错并且中断
Java中异常够用吗?
现实生活中,问题可能是方方面面的,比较多的问题 ,Java异常够吗?
不够,我们可以自己定义异常并抛出 JVM只能抛出以及存在的异常体系中的对象 所以我们可以手动抛出自定义异常
异常处理
声明:在当前异常发生的函数后面 throws 异常类名
void show() throws XxxException{
throw new XxxException();
}
就是告诉调用者可能会出现问题,如果真的出现问题了,由调用者来决定怎么去处理 ——声明/捕获
声明仅仅是告诉外界自身可能会有问题,但是这个问题自身没有去真正解决
捕获:就是当前自身去解决问题
try{
//尝试着去执行某些代码
throw new XxxException
}catch(XxxException e){//一旦try中出现异常 则catch将其捕获
e.printStackTrace();//打印异常
//异常处理
}
public class Test {
public static void main(String[] args) {
try {
sleep(99);//time > 72,调用者捕获异常,进行处理
} catch (SleepTimeCannotMoreThanSeventyTwo sleepTimeCannotMoreThanSeventyTwo) {
sleepTimeCannotMoreThanSeventyTwo.printStackTrace();
}
System.out.println("Hello");//可以正常执行
}
public static void sleep(int time) throws SleepTimeCannotMoreThanSeventyTwo {//throws声明异常
if(time < 0){//捕获异常,自行处理
try {
throw new SleepTimeCannotLessThanZero("睡眠时间不能小于0小时");
} catch (SleepTimeCannotLessThanZero e) {
e.printStackTrace();
time = 0;
}
}
if(time > 72){//没有捕获,声明异常,让调用者处理
throw new SleepTimeCannotMoreThanSeventyTwo("睡眠时间不能大于72小时");
}
System.out.println("小米睡了"+ time +"小时");
}
}
class SleepTimeCannotLessThanZero extends Throwable{
public SleepTimeCannotLessThanZero(String message) {
super(message);
}
}
class SleepTimeCannotMoreThanSeventyTwo extends Throwable{
public SleepTimeCannotMoreThanSeventyTwo(String message) {
super(message);
}
}
package com.company;
/*
老师上课 ——老师 电脑
老师 —— 姓名 teach(){}
电脑 —— 开机 蓝屏 冒烟*/
public class Test {
public static void main(String[] args) {
Teacher teacher = new Teacher("张老师");
try {
teacher.teach();
} catch (TeachingDisruptException e) {
e.printStackTrace();
System.out.println("放假...");
//由于电脑冒烟(电脑) —— 产生课程无法继续的问题(老师看到的) —— 向学校抛出课程无法继续的异常
}
}
}
class Teacher{
String name = new String();
Computer computer = new Computer();
public Teacher(String name) {
this.name = name;
}
public void teach() throws TeachingDisruptException{//老师不能自行解决,所以声明冒烟异常
try {
computer.start();
} catch (BlueScreenException e) {
e.printStackTrace();//打印异常信息
computer.restart();
}catch (MaoYanException e){
//一旦产生电脑冒烟的问题,就会导致产生课程无法继续的问题
/*
* 异常的转换
* 每一个层级都要去考虑不同的结果
* 第一层出现异常A 导致第二层出现异常B......
* */
e.printStackTrace();
throw new TeachingDisruptException("课程无法继续咯!");//抛出新异常 老师无法解决 继续声明
}
System.out.println(name + "开始上课了...");
}
}
class Computer{
int statue = 0;//电脑状态 0正常 1蓝屏 2冒烟
public void start() throws BlueScreenException, MaoYanException {
System.out.println("笔记本开机啦!");
if(statue == 1){
throw new BlueScreenException("电脑蓝屏咯!");//电脑不能自行解决蓝屏,所以声明异常
}
if(statue == 2){
throw new MaoYanException("电脑冒烟咯!");//电脑不能自行解决冒烟,所以声明异常
}
}
public void restart(){
System.out.println("笔记本重启");
}
}
class TeachingDisruptException extends Exception{
public TeachingDisruptException(String message){
super(message);
}
}
class BlueScreenException extends Exception{
public BlueScreenException(String message) {
super(message);
}
}
class MaoYanException extends Exception{
public MaoYanException(String message) {
super(message);
}
}
finally关键字
try catch 如果发现异常 则会进行程序的跳转动作 从try中第一次出现异常的地方跳转至catch
注意:如果手动的将异常throw,在这之后的代码就成为了不可达(不会执行)
我们将必须要执行的代码放进finally
try{
//尝试去执行一些代码
}catch(){
//如果try中出现异常 则catch中将其捕获并修正
}finally{
//无论异常是否发生 都要去执行的代码
}
public class Test {
public static void main(String[] args) {
try {
System.out.println("Code1...");
System.out.println("Code2...");
System.out.println(10/0);
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("Code3...");
System.out.println("必须要执行的代码");
}
}
}
什么情况使用finally?
IO,数据库连接,网络编程
上述三者都会占用内存资源,如果用完之后不去释放资源,则会导致内存浪费,所以我们无论在操作过程中是否产生异常,上述资源都要被释放掉
在继承当中使用异常的情况
-
父类的函数如果没有声明任何编译时异常 那么子类重写的函数也不能声明
就算子类中出现了编译时异常 也只能进行捕获
-
父类的函数如果声明了编译时异常 那么子类重写的函数只能声明该异常以及该异常的子类
-
父类的函数如果声明了多个编译时异常 那么子类重写的函数 只能声明这些异常以及这些异常的子类