一、异常的概念及分类
Exception:异常,代表程序可能出现的问题
Exception分为两类:
1、运行时异常:RuntimeException以及其子类,编译阶段不会出现异常提醒,在运行阶段会出现异常提醒
2、编译时异常:编译阶段出现异常提醒
二、异常处理的方式
1、JVM默认的处理方式
把异常的原因、异常的名称、异常出现的位置以红色字体打印在控制台
程序停止执行,异常后面的代码不会再执行
public class test1 {
public static void main(String[] args) {
/*
1、JVM默认的处理方式
把异常的原因、异常的名称、异常出现的位置以红色字体打印在控制台
程序停止执行,异常后面的代码不会再执行
*/
System.out.println("你好");
System.out.println(1/0);
System.out.println("我的世界");
System.out.println("java");
// 你好
// ArithmeticException
// 只会输出你好和异常信息 出现异常后面的代码不会再执行
}
}
2、自己处理捕获异常
如果自己不捕获并处理异常 系统就会处理异常 那么就在控制台输出错误信息 并终止程序 如果我们不想要终止程序就必须自己捕获并处理异常 这就是自己捕获并处理异常的好处
(1)语法
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
快捷键:
选中可能出现异常的代码 ctrl+alt+t
目的:
当代码出现异常时,可以让程序继续往下执行
public class test1 {
public static void main(String[] args) {
/*
2、自己处理
语法:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
*/
System.out.println("我的世界");
/*
此处出现算术异常,程序会创建一个码ArithmeticException类的对象 new ArithmeticException()
然后拿着这个对象与catch的小括号中的对象进行对比 看是否匹配
如果能接收 那么异常就会捕获 就会执行catch里面的代码
当执行完try...catch后 程序会继续往下执行 输出java
*/
try {
// 可能出现异常的代码
System.out.println(1/0);
}catch (ArithmeticException e){
// 出现异常代码后执行的操作
System.out.println("算术异常 被除数不能是0");
}
// 执行完try...catch后 程序会继续往下执行
System.out.println("java");
// 输出:
// 我的世界
// 算术异常 被除数不能是0
// java
}
}
(2)注意
1、如果try中代码没有出现异常,那么系统会执行完try中所有的代码,不会执行catch语句体(只有try语句体出现异常才会执行catch语句体)
public class test1 {
public static void main(String[] args) {
/*
2、自己处理
语法:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
*/
try {
// 可能出现异常的代码
// 当没有出现异常时 会执行完所有的代码
System.out.println("你好");
System.out.println("java");
}catch (ArithmeticException e){
// 出现异常代码后执行的操作
// 当没有出现异常时 不会执行代码
System.out.println("算术异常 被除数不能是0");
}
// 执行完try...catch后 程序会继续往下执行
System.out.println("我的世界");
// 输出:
// 你好
// java
// 我的世界
}
}
2、如果try中代码有多个异常,但是catch中罗列的异常情况没有包括try中的所有异常,程序可能终止,可能不终止
如果程序没有捕获到异常就会终止程序(相当于try...catch白写了 最终还是交给虚拟机进行处理) 如果捕获到了就不会终止程序
public class test1 {
public static void main(String[] args) {
/*
2、自己处理
语法:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
*/
int [] arr=new int[] {1,2,3,4,5};
try {
// 可能出现异常的代码
System.out.println(arr[10]);
System.out.println(1/0);
}catch (ArithmeticException e){
// 出现异常代码后执行的操作
System.out.println("算术异常 被除数不能是0");
}
System.out.println("我的世界"); // 因此不会输出我的世界
/*
分析:System.out.println(arr[10]);出现了索引异常 就会与catch括号中的异常进行匹配
现在 ArithmeticException e 与 new ArrayIndexOutOfBoundsException()无法匹配
错误捕获不到
由于 ArrayIndexOutOfBoundsException 异常没有在 catch 块中被捕获处理,程序会在此处中断,不会继续执行后面的代码
*/
// 输出:
// ArrayIndexOutOfBoundsException
}
}
public class test1 {
public static void main(String[] args) {
/*
2、自己处理
语法:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
*/
int [] arr=new int[] {1,2,3,4,5};
try {
// 可能出现异常的代码
System.out.println(1/0);
System.out.println(arr[10]);
}catch (ArithmeticException e){
// 出现异常代码后执行的操作
System.out.println("算术异常 被除数不能是0");
}
System.out.println("我的世界");
/*
分析:System.out.println(1/0);出现了算术异常 就会与catch括号中的异常进行匹配
因此trySystem.out.println(arr[10]);就不会执行(即使有错误也执行不到)
现在 ArithmeticException e 与 new ArithmeticException()匹配
错误捕获到 由于捕获到错误就会执行catch的语句体
执行完try...catch之后 程序继续往下执行 输出我的世界
*/
// 输出:
// 算术异常 被除数不能是0
// 我的世界
}
}
解决方法:写多个catch语句罗列所有的异常情况,如果这些异常存在父子关系,那么父类一定要写在最下面
根据多态的概念 父类可以接收子类的对象 如果将父类异常放在上面 那么try语句体出现的异常都会被父类异常接收 那么父类异常下面的异常永远执行不到
在JDK7以后 如果多个catch的语句体执行的操作是一样的 那么异常可以写在一个catch语句体中
注意:写在同一个catch括号中的异常不能存在父子关系 各个异常之间用|隔开 不能用||隔开
public class test1 {
public static void main(String[] args) {
/*
2、自己处理
语法:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
*/
int [] arr=new int[] {1,2,3,4,5};
try {
// 可能出现异常的代码
// 每次只捕获一个错误 捕获到了就执行catch语句体
System.out.println(1/0);
System.out.println(arr[10]);
}catch (ArrayIndexOutOfBoundsException |ArithmeticException e){
// 不能写成ArrayIndexOutOfBoundsException ||ArithmeticException e
// 或者ArrayIndexOutOfBoundsException e|ArithmeticException e
// 出现异常代码后执行的操作
System.out.println("异常");
}
System.out.println("我的世界"); // 为什么不能输出
}
}
(3)问题总结
(4)对异常常见的处理方法
1、异常对象名称.getMessage();
该方法返回有关异常的简短描述
public class test1 {
public static void main(String[] args) {
/*
2、自己处理
语法:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
*/
int [] arr=new int[] {1,2,3,4,5};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
// e.getMessage() 返回值是有关异常的简短描述
String str= e.getMessage();
System.out.println(str);
}
System.out.println("我的世界");
// Index 10 out of bounds for length 5
// 我的世界
}
}
2、异常对象名称.toString();
该方法返回有关异常的简短描述
public class test1 {
public static void main(String[] args) {
/*
2、自己处理
语法:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
*/
int [] arr=new int[] {1,2,3,4,5};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
// e.getMessage() 返回值是有关异常的简短描述
String str= e.toString();
System.out.println(str);
}
System.out.println("我的世界");
// java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 5
// 我的世界
}
}
3、异常对象名称.printStackTrace();
无返回值 直接在控制台以红色字体打印异常信息 不会终止程序
3、抛出异常
用于方法中可能出现的异常
(1)throws
写在方法的定义处,表示声明一个异常,告诉调用者使用本方法可能会有哪些异常,如果是运行时异常,那么throws在方法定义处抛出的异常可以不写,但如果是编译时异常,那么throws在方法定义处抛出的异常必须要写
语法:
public void 方法() throws 异常类名1,异常类名2...{
....
}
(2)throw
写在方法内,结束方法,手动抛出异常对象,交给调用者,方法中异常下面的代码就不再执行力
语法:
public void 方法() {
throws 异常类名1,异常类名2...
}
public class test1 {
public static void main(String[] args) {
// 对抛出的异常 我们需要进行处理 可以采取自己捕获错误的方式 try...catch
int [] arr=new int[0];
try {
System.out.println(getMax(arr));
} catch (NullPointerException e) {
System.out.println("空指针异常");
}catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界访问异常");
}
}
// throws NullPointerException,ArrayIndexOutOfBoundsException
// 这段代码告诉调用者 调用getMax方法可能会出现NullPointerException,ArrayIndexOutOfBoundsException的错误
// 因为NullPointerException,ArrayIndexOutOfBoundsException都属于运行时异常RuntimeException
// 因此在方法头定义处可以不写throws NullPointerException,ArrayIndexOutOfBoundsException
public static int getMax (int [] arr)throws NullPointerException,ArrayIndexOutOfBoundsException{
// 当数组为null意味着该数组变量不指向任何数组的内存地址
if(arr==null){
// 抛出空指针异常给调用者
throw new NullPointerException();
}
// 当没有数组元素时 抛出索引越界异常
if(arr.length==0){
// 抛出索引越界异常给调用者
throw new ArrayIndexOutOfBoundsException();
}
int max=arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i]>max){
max=arr[i];
}
}
return max;
}
}
抛出异常通常和捕获异常相结合
三、自定义异常
创建步骤:
1、定义异常类
类名见名知意
2、写继承关系
如果是编译时异常就继承Exception
如果是运行时异常就继承RuntimeException
3、定义空参构造
4、定义带参构造