异常的概念
- 基本概念:
将程序执行中发生的不正常行为情况称为异常。
【说明】不正常行为不包括:语法错误、逻辑错误 - 异常的分类
- Error:Java虚拟机无法解决的严重问题,如:
StackOverflowError
栈溢出,OOM
(out of memory) - Exception:其他因编程错误/偶然的外在因素导致的一般性问题,分为运行运行时异常和编译时异常
- 运行时异常,编译器不要求强制处理,可以不做处理;若全处理可能会影响程序的可读性和效率
- 编译时异常,编译器要求必须强制处理
异常体系图
- 查看异常体系图
- 输入
Throwable
+快捷键Ctrl+B - 打开图表Diagrams
3.显示实现Show Implementations
- 异常体系图
- java.lang.RuntimeException类以及其子类都是运行时异常
常见的异常
五大运行时异常
- 空指针异常(NullPointException):当程序试图在需要对象的地方使用null时,抛出该异常
public class NullPointException {
public static void main(String[] args) {
String s=null;
System.out.println("s字符串的长度:"+s.length());
}
}
- 数学运算异常( ArithmeticException ):当出现异常的运算条件时抛出
public class ArithmeticException {
public static void main(String[] args) {
int a=1;
int b=0;
System.out.println("a/b="+a/b);
}
}
- 数组下标越界异常(ArrayIndexOutOfBoundsException):用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引
public class ArrayIndexOutOfBoundsException {
public static void main(String[] args) {
int []a={1,2,3};
for (int i = 0; i <= a.length; i++) {
System.out.println(a[i]);
}
}
}
- 类型转换异常(ClassCastException ):当试图将对象强制转换为不是实例的子类时,抛出该异常
class A{}
class B extends A{}
class C extends A{}
public class ClassCastException {
public static void main(String[] args) {
A b = new B();//向上转型
b=(B)b;//向下转型
b=(C)b;
}
}
- 数字格式不正确异常(NumberFormatException):当应用程序试图将字符串转换成一种数值类型但该字符串不能转换为适当格式时
public class NumberFormatException {
public static void main(String[] args) {
String s="韩顺平yyds";
int n;
n=Integer.parseInt(s);
System.out.println(n);
}
}
编译时异常(略)
异常处理
异常处理的概念
- 基本概念:当异常发生时的对异常的处理方式
- 异常处理的方式:
- try-catch- [finally]
try{
//可能出现异常的代码
}catch(Exception e){
//异常捕获
//1.异常发生——> 系统将异常封装成Excepiton的对象e传递给catch ——> 执行自己编写异常代码
//2.异常不发生——> 直接跳过catch
}
finally{
//finally可有可无
//不管异常是否发生,finally代码一定会执行
//所以一般finally中放释放资源的代码
}
① 对代码异常处理快捷键 ctrl+alt+T
② 可以有多个catch语句来捕获不同的异常,但要求子类异常在前,父类异在后;若顺序相反则会导致子类异常失效
③ 如①所示,异常处理的组合可以有三种,try/finally
组合相当于没有捕获异常,因此程序将直接崩掉(有异常)/退出(无异常)
- throws:方法声明中用throws可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常/异常的父类
① 编译异常:必须用throws或try-catch-finally处理
② 运行异常:可以不敲代码处理,默认throws处理
③ 子类重写父类的方法时,而父类的方法中有throws,子类在重写父类的方法时需要把throws后面的异常类型写成父类异常类的子类或当前类
练习
Q1:输出为?
public class TryCatchExercise01 {
static int method(){
try {
String[]name=new String[3];
if(name[1].equals("jack")){
System.out.println(name[1]);
}else{
name[3]="tom";
}
return 1;
} catch (ArrayIndexOutOfBoundsException e) {
return 2;
}catch (NullPointerException e){
return 3;
} finally {
return 4;
}
}
public static void main(String[] args) {
System.out.println(method());
}
}
name[1]
为null因此在第一个if判断时出现异常,在NullPointerException
捕获异常,但由于finally是必须执行的所以return4
。输出结果为:4.
Q2:输出为?
public class TryCatchExercise02 {
static int method(){
int i=1;
try {
i++;
String[]name=new String[3];
if(name[1].equals("jack")){
System.out.println(name[1]);
}else{
name[3]="tom";
}
return 1;
} catch (ArrayIndexOutOfBoundsException e) {
return 2;
}catch (NullPointerException e){
return ++i;
} finally {
return ++i;
}
}
public static void main(String[] args) {
System.out.println(method());
}
}
name[1]
为null因此在第一个if判断时出现异常,在NullPointerException
捕获异常,执行return ++i
此时i=3存放在一个临时变量中,但由于finally是必须执行的所以执行return ++i
,此时返回4。输出结果为:4.
Q3:输出为?
public class TryCatchExercise03 {
static int method(){
int i=1;
try {
i++;//i=2
String[]name=new String[3];
if(name[1].equals("jack")){
System.out.println(name[1]);
}else{
name[3]="tom";
}
return 1;
} catch (ArrayIndexOutOfBoundsException e) {
return 2;
}catch (NullPointerException e){
return ++i;
} finally {
++i;
System.out.println(i);
}
}
public static void main(String[] args) {
System.out.println(method());
}
}
name[1]
为null因此在第一个if判断时出现异常,在NullPointerException
捕获异常,执行return ++i
此时i=3存放在一个临时变量中,但由于finally是必须执行的所以执行++i
,此时i=4,输出4;因为函数需要返回值,所以返回捕获异常的语句,返回3。输出结果为:4 3
Q4:①②是否正确?
public static void func1(){
func2();//①
}
public static void func2() throws ArrayIndexOutOfBoundsException{
}
public static void fun3(){
func4();//②
}
public static void func4() throws FileNotFoundException{
}
ArrayIndexOutOfBoundsException
属于运行异常,当func2()出现异常时,func1()默认throws,因此func2()正确FileNotFoundException
属于编译异常,当func4()出现异常时,func3()必须写出两大异常处理的方式中的任意一种,因此func4()有误
自定义异常定义:若程序中出现某种错误,但错误信息不在Throwable的子类中,那么就可以自己设计异常类,用于描述该错误信息
如何自定义异常:
- 自定义异常类名继承Exception或RuntimeException
【说明】
① 继承Exception ——> 属于编译异常
② 继承RuntimeException ——> 属于运行异常
一般继承RuntimeException,这样就可以使用默认异常处理机制
//检查月份是否合法,若不合法抛出异常,若合法显示当前为几月 class MonthException extends RuntimeException{ public MonthException(String s) { super(s); } } public class CustomException { public static void main(String[] args) { //输入一个月份 int month=13; if(month<=0||month>=13) throw new MonthException("月份错误!"); else System.out.println("当前月份为"+month+"月"); } }
- 自定义异常类名继承Exception或RuntimeException
意义 | 位置 | 后跟的东西 | |
throws | 异常处理的一种机制 | 方法声明末尾 | 异常类型 |
throw | 手动生产异常对象的关键字 | 方法体中 | 异常对象 |