Java学习笔记-Day22 Java 异常处理
一、异常
API中标准异常的顶级父类是Throwable类。
Throwable类有两个子类:Exception和Error。所有异常都是Exception类的直接或间接子类。所有错误都是Error的直接或间接子类。
1、异常(Exception)
异常(Exception):异常是指程序运行时发生的不正常事件,会影响后续代码的执行。异常能被程序处理,保证程序继续执行。
Exception有很多子类,这些子类又可以分为两大类,即运行时异常和非运行时异常。RuntimeException的子类都是运行时异常,其他的都是非运行时异常。
运行时异常:运行时异常也称为非检测异常,这些异常在编译期不检测,程序中可以选择处理,也可以不处理。如果不处理,在运行时抛出异常,中断执行,但是编译是通过的。
非运行时异常:非运行时异常也称为检测异常,在编译期就会被检测,并强制处理,不处理则会发生编译错误。
2、常见异常
(1)NullPointerException(空指针异常)
发生前提:当对一个空对象,即没有初始化,依然为null的对象调用属性或方法时。
(2)ArithmeticException(数学异常)
发生前提:例如,整数除以0时发生。
(3)IndexOutOfBoundsException(索引越界异常)
包括字符串索引StringIndexOutOfBoundsException和数组索引ArrayIndexOutOfBoundsException两种。
发生前提:当访问字符串中的字符或者数组中的元素,超过了其长度时。
(4)NumberFormatException(数字格式异常)
发生前提:当把一个字符串转换成数字时,但字符串内容不是数字时发生。
(5)ClassCastException(类型转换异常)
发生前提:把父类对象转换成不相关的子类类型时。
3、异常处理语法
3.1、try-catch语句
try-catch语句:主动处理,出现在方法内部。把所有可能抛出异常的,或者肯定抛出异常的代码都写到try代码块中。catch语句紧随try语句后,用来捕获异常并进行处理。当try块中代码抛出了异常对象后,异常处理机制就将这个对象的类型与try后的catch语句中的异常类型进行匹配,如果类型相同,或者抛出的是捕获的子类,就称为匹配成功,那么异常就被捕获,就运行catch块中的语句。否则,称为异常没有被捕获,程序将中断。
try {
int[] i = {1,2,3};
i[4]=10;
} catch (Exception e) {
System.out.println("数组下标越界异常");
e.printStackTrace();
}
如果try语句中有多行代码,有可能抛出多种类型异常,那么可以使用多个catch语句,但是try语句中只会发生一种异常,因为发生异常后,try语句中的在发生异常的代码之后的代码发生中断,不会再执行。
注意:catch语句的异常类型必须从子类到父类的顺序,否则编译错误。
try {
String s = null;
int a = 4/0;//会发生数学异常
s.length();//会发生空指针异常
} catch (ArithmeticException e) {
System.out.println("数学异常");
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标超出异常");
} finally {
System.out.println("finally");
}
3.2、try-catch-finally语句
try-catch-finally语句:主动处理,出现在方法内部。
try {
int[] i = {1,2,3};
i[4]=10;
} catch (Exception e) {
System.out.println("数组下标越界异常");
}finally{
System.out.println("finally");
}
catch语句可以有多个。catch语句的异常类型必须从子类到父类的顺序,否则编译错误。
try {
String s = null;
int a = 4/0;
s.length();
} catch (ArithmeticException e) {
System.out.println("数学异常");
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标超出异常");
} finally {
System.out.println("finally");
}
finally块前有return语句,finally依然被执行。
public class Demo {
public int show(int x){
try {
System.out.println(x/0);
return 0;
} catch (Exception e) {
System.out.println("catch");
return 1;
} finally {
System.out.println("finally");
}
}
public static void main(String[] args) {
int i = new Demo8().show(1);
System.out.println(i);//1
}
}
finally块前有System.exit(0)语句,finally不被执行。
public class Demo {
public void show(int x){
try {
System.out.println(x/0);
System.exit(0);
} catch (Exception e) {
System.out.println("catch");
System.exit(0);
} finally {
System.out.println("finally");
}
}
public static void main(String[] args) {
new Demo().show(1);
}
}
一个try可以搭配一个catch,但是catch中可以使用逻辑或运算符 | 来处理多个异常,多个异常的等级是平等的。
try {
String s = null;
int a = 4/0;
s.length();
} catch (ArithmeticException | NullPointerException | ArrayIndexOutOfBoundsException e) {
System.out.println("异常");
} finally {
System.out.println("finally");
}
3.3、throws
throws:向上抛出异常,谁调用就抛给谁。throws用在方法声明处,在方法名的后面添加 throws 异常类型
,声明该方法可能发生的异常类型。一个方法如果使用了throws,那么调用该方法时,编译期会提醒必须处理这些异常,否则编译错误。throws后可以声明多种类型,用逗号隔开即可。抽象方法也可以使用throws声明该方法可能抛出的异常类型。
public static void main(String[] args) throws ParseException {
new SimpleDateFormat("yyyy-MM").parse("2019-12");
}
3.4、throw
抛出异常是创建了一个异常对象(制造异常,手动引发一个异常),然后用throw关键字交给异常处理机制去处理。throw关键字在方法体中使用。运行时异常是JVM自动抛出,非运行时异常需要程序员用throw关键字抛出。
public class Demo {
public static void div(int x,int y) throws Exception{
if (y == 0) {
throw new Exception();
} else {
System.out.println("x/y="+x/y);
}
}
public static void main(String[] args) throws Exception {
div(1,0);
}
}
3.5、自定义异常类
3.5.1、自定义异常类的步骤
① 继承API中任意一个标准异常类,多数情况下,继承Exception类,也可以选择继承其他类型异常。
② 自定义异常类中不写其他方法,只重载必要的构造方法。
public class CalcException extends Exception{
private static final long serialVersionUID = -4609210213752895914L;
public CalcException() {
super();
}
public CalcException(String message) {
super(message);
}
}
3.5.2、自定义异常类的使用
使用自定义异常与使用API中标准异常一样,可以用throw抛出自定义异常对象,然后使用throws声明自定义异常类型或者try-catch-finally语句处理异常。
public class Demo {
public static void div(int x,int y) throws CalcException {
if (y == 0) {
throw new CalcException("除数不能小于0");
} else {
System.out.println("x/y="+x/y);
}
}
public static void main(String[] args) {
try {
div(1,0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.6、断言
JDK1.4版本开始,增加了断言机制。断言用来进行调试,不在生产环境中使用。
断言使用关键字assert表示,有两种形式:
当布尔表达式的值是true时,忽略assert。当布尔表达式的值是false时,发生AssertionError错误,程序中断。如果用第二种形式的话,则会同时显示错误信息。
public class TestAssert {
public void show(int i) {
System.out.println("11111");
//assert i != 0;
assert i != 0:"输入应不等于0";
System.out.println("22222");
}
public static void main(String[] args) {
new TestAssert().show(0);
}
}
Eclipse默认没有开启断言功能。开启Eclipse中的断言功能,要在 Window -> preference -> Java -> Installed JREs -> Edit -> Default VM argument 中添加参数:-ea
。
二、错误(Error)
错误(Error):错误程序没法处理,发生错误后,一般虚拟机会选择终止程序运行,需要修改代码才能解决相关错误。
java.lang.StackOverflowError(内存泄漏)
public class Demo {
public static void main(String[] args) {
main(null);
}
}