文章目录
异常
1、什么是异常?,java提供异常处理机制有什么用?
程序执行过程中,发生了不正常的情况,这种不正常的情况就是:异常
Java把异常信息打印到输出的控制台 (JVM打印的),供程序员参考,程序员看到后,会进行修改
让程序更加健壮
2、异常在java中以类的形式存在,每一个异常类都可以创建异常对象
3、异常在生活中的体现:
火灾(异常类):
小明家着火了(异常对象)
小红家着火了(异常对象)
小黑家着火了(异常对象)
1、Java的异常处理机制
1.1异常在Java中以类和对象的形式存在,异常的继承结构:
Object
Object下有Throwable(可抛出的)
Throwable下有两个分支:
Error(不可处理,直接退出JVM)和Exception(可处理的)
Exception下有两个分支:
Exception的直接子类:编译时异常(要求程序员在编写程序阶段就必须预先对这些异常进行处理)
RuntimeException:运行时异常(在编写程序阶段程序员可以预先处理,也可以不管)
1.2、编译时异常和运行时异常,都发生在运行阶段。编译阶段异常是不会发生的。
编译时异常因为什么得名?
因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。
所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象。
因为异常的发生就是new异常对象。
1.3、 编译时异常和运行时异常的区别?
编译时异常一般发生的概率比较高。
举个例子:
看见外面下大雨,出门前就会预料到:
不打伞可能会生病(一种异常),所以拿一把伞
”拿伞“就是对”生病“异常发生之前的一种处理方式
对于一些发生概率较高的异常,需要在运行之前对其进行预处理。
运行时异常一般发生的概率比较低。
举个例子:
小明走在大街上,可能被天上的飞机轮子砸到(异常)。
在出门之前没有必要提前对这种发生概率低的异常进行预处理。
如果处理这种异常,活得很累
1.4、编译时异常还有其他的名字:
受检异常
受控异常
1.5、运行时异常还有其他的名字:
未受检异常
非受控异常
1.6、Java语言中对异常的处理包括两种方式:
第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。
第二种方式:使用try...catch语句进行异常的捕捉。
可以有多个catch(从小到大)
什么时候用throws?
当需要将异常上报的时候用throws
1.8、注意:
Java中异常发生以后如果一直上抛,最终抛给了main方法,main方法继续
向上抛,抛给了调用者JVM,JVM知道了这个异常发生,只有一种结果,终止
java程序的执行。
1.9、异常对象有两个重要的方法:
获取异常简单的描述信息:
String msg = exception.getMessage();
打印异常追踪的堆栈信息:
exception.printStackTrace();
java.lang.Throwable类是 Java语言中所有错误或异常的父类
Exception:编译期异常,进行编译(写代码)java程序中出现的问题
RuntimeException:运行期异常,java程序运行过程中出现的问题(我们不用处理,默认交给JVM处理)
异常就相当于程序得了小毛病(感冒),把异常处理掉,程序可以继续执行
Error:错误
错误就相当于程序的了一个无法治疗的毛病,必须修改源代码,程序才能继续执行
throw关键字
作用:
可以使用throw关键字在指定的方法中抛出指定的异常
使用格式:
throw new XXXException("异常产生的原因");
注意:
1、throw关键字必须写在方法的内部
2、throw关键字后边new的对象必须是Exception或者Exception的子类对象
3、throw关键字抛出指定的异常对象,我们就必须处理这个异常对象
throw关键字后面创建的是RuntimeException或者是其子类,我们可以不处理,默认交给JVM处理
throw关键字后面创建的是编译异常(写代码时报错),我们必须处理这个异常,要么throws要么try...catch
public class DemoThrow {
public static void main(String[] args) {
int arr[]={1,2,3,4,5};
getElement(arr,3);
// int arr1[] = null;
// getElement(arr1,2);//NullPointerException: 传递的数组值为null
int arr2[] = {1,2,3,4};
getElement(arr2,6);//ArrayIndexOutOfBoundsException: 索引越界
}
//定义一个方法,获取数组指定索引的元素
public static int getElement(int[] arr,int index){
//我们要对传递过来的参数--数组,进行合法性校验
//如果数组arr的值是null,我们抛出空指针异常
//告诉调用者“传递的数组值为null”
if(arr == null){
//NullPointerException是运行期异常,我们不用处理,交给JVM
throw new NullPointerException("传递的数组值为null");
}
//我们可以对传递过来的参数--index进行合理性校验
//如果index的范围不在数组的索引范围中,我们就抛出数组索引越界异
//告诉调用者“索引越界”
if(index<0 || index>arr.length-1){
//ArrayIndexOutOfBoundsException是运行期异常
throw new ArrayIndexOutOfBoundsException("索引越界");
}
int ele = arr[index];
System.out.println(ele);
return 0;
}
}
throws 抛出异常给JVM,一旦出现异常就在控制台打印异常信息,并且不会继续执行下面的代码了
public class DemoThrows {
public static void main(String[] args) throws ParseException {
//Exception:编译期异常
SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd");//用来格式化日期
Date date = sdf.parse("1999-04-29");//把字符串格式的日期,解析为Date格式的日期
System.out.println(date);//Thu Apr 29 00:00:00 CST 1999
Date date1 = sdf.parse("1999-0429");
System.out.println(date1);//Exception in thread "main" java.text.ParseException: Unparseable date: "1999-0429"
System.out.println("后续");//无法执行
}
}
try…catch处理异常,遇到异常会在控制台打印出异常信息,并且会继续执行后面的代码
public class DemoTry {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd");
Date date = null;
try {
date = sdf.parse("1999-0429");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(date);//java.text.ParseException: Unparseable date: "1999-0429" null
System.out.println("后续");//后续(执行)
}
}
异常对象有两个重要的方法:
获取异常简单的描述信息:
String msg = exception.getMessage();
打印异常追踪的堆栈信息:
exception.printStackTrace();
public class Demo02 {
public static void main(String[] args) {
NullPointerException e = new NullPointerException("空指针异常");
//获取异常简单信息描述:这个信息实际上就是构造方法上面string参数
String msg = e.getMessage();
System.out.println(msg);//空指针异常
//打印异常堆栈信息
//java后台打印异常堆栈信息,采用了异步线程的方式
e.printStackTrace();//java.lang.NullPointerException: 空指针异常 at cf.daunzifan.JavaTest.Day07.Exception.Demo02.main(Demo02.java:9)
}
}
关于try…catch中的finally子句:
1、在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
2、finally语句通常使用在哪些情况:
通常在finally语句块中完成资源的释放/关闭。
因为finally中的代码有保障
即使try中出现异常,也会执行
public class Demo03 {
public static void main(String[] args) {
/*
try不能单独使用
try finally可以联合使用(可以没catch)
下面代码的执行顺序:
先执行try...
再执行fin...
最后执行return
*/
try{
System.out.println("try..");
return;
}finally {
System.out.println("fin....");
}//try..//fin....
}
}
final finally finalize的区别?
public class Demo05 {
public static void main(String[] args) {
final int I = 100;
//final是一个关键字,表示最终的
//final修饰的类无法继承
//final修饰的方法无法覆盖
//final修饰的变量无法重新赋值
//finally也是一个关键字,和try联合使用,使用在异常处理机制中
//finalize()是Object类中的一个方法,是标识符
//这个方法是由垃圾回收器GC负责调用的
}
}
自定义异常
两步:
1、编写一个类继承Exception或者RuntimeException
2、提供两个构造方法,一个无参数,一个带有String参数的。
public class MyException extends Exception {//编译时异常
public MyException() {
}
public MyException(String message) {
super(message);
}
}
/*
public class MyException extends RuntimeException {//运行时异常
}
*/
public class MyExceptionTest {
public static void main(String[] args) {
//创建异常对象(只new了异常对象,并没有手动抛出(throw e))
MyException e = new MyException("自己的异常");
//throw e;//手动抛出
//合并写法
//throw e = new MyException("自己的异常");
//打印异常堆栈信息
e.printStackTrace();//cf.daunzifan.JavaTest.Day07.Exception.MyException: 自己的异常
//获取异常简单描述信息
String msg = e.getMessage();
System.out.println(msg);//自己的异常
}
}
异常原理解析