异常
异常:程序在运行过程中出现的特殊情况。
必要性:
任何程序都可能存在大量的未知问题、错误。
如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
一、异常
1.1异常分类
异常分类图:
Throwable:可抛出的,一切异常或错误的父类,位于java.lang包中
Error:JVM、硬件、执行逻辑错误,不能手动抛出。常见:StackOverflowError、OutOfMemoryError等
Exception:程序在运行和配置中产生的问题,可处理
一般性异常( CheckedException ):检查时异常,必须处理
RuntimeException:运行时异常,可处理,可不处理
常见运行时异常:
异常 | 描述 |
---|---|
NullPointerException | 空指针异常 |
ArrayIndexOutOfBoundsException | 数组越界异常 |
ClassCastException | 类型转换异常 |
NumberFormatException | 数字格式化异常 |
ArithmeticException | 算术异常 |
1.1.1异常的产生
- 自动抛出异常:当程序在运行时遇到不符合规范的代码或结果时,会产生异常。
- 手动抛出异常:语法:throw new 异常类型(“实际参数”)。
- 产生异常结果:相当于遇到 return语句,导致程序因异常而终止。
1.1.2异常传递
-
异常的传递:
按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。
-
受查异常:throws 声明异常,修饰在方法参数列表后端。
-
运行时异常:因可处理可不处理,无需声明异常。
1.2异常处理
Java的异常处理是通过5个关键字来实现的:
- try:执行可能产生异常的代码 。
- catch:捕获异常 ,并处理。
- finally:无论是否发生异常,代码总能执行。
- throw: 手动抛出异常 。
- throws:声明方法可能要抛出的各种异常。
1.2.1try-catch-finally
语法:
try…catch:
try {
//可能出现异常的代码
} catch(Exception e) {
//异常处理的相关代码,如:getMessage()、printStackTrace()
}
try…catch…finally:
try {
//可能出现异常的代码
} catch(Exception e) {
//异常处理的相关代码,如:getMessage()、printStackTrace()
} finally{
//是否发生异常都会执行,可以释放资源等。
}
关闭资源
return :是结束当前方法----应该要资源释放了
System.exit(0):退出虚拟机所有的资源回收,没必要在执行finally
多重catch:
try{
//可能出现异常的代码。
}catch(异常类型1){
//满足异常类型1执行的相关代码。
}catch(异常类型2){
//满足异常类型2执行的相关代码。
}catch(异常类型3){
//满足异常类型3执行的相关代码
}
(多重catch,遵循从子( 小 )到父( 大 )的顺序,父类异常在最后。)
try…finally…不能捕获异常 ,仅仅用来当发生异常时,用来释放资源。
一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。
语法:
try{
//可能出现异常的代码
}finally{
//是否发生异常都会执行,可以释放资源等}
示例:
public class TestTry {
public static void main(String[] args) {
try {
Scanner input = new Scanner(System.in);
System.out.println("请输入一个整数:");
int num1 = input.nextInt();
System.out.println("请输入除数");
int num2 = input.nextInt();
System.out.println(num1 + "/" + num2 + "=" + num1/num2);
}catch (InputMismatchException e) {
System.out.println("输入不为整数");
return;
}catch (ArithmeticException e) {
System.out.println("除数不能为0");
System.exit(0);
} catch (Exception e) {
System.out.println("其它异常");
}finally {
System.out.println("有没有异常都会执行,return也会输出,System.exit()不会输出");
}
}
}
1.3声明抛出异常
Java程序在执行过程中如果出现异常,会自动生成一个异常类对象,该异常对象将被自动提交给JVM, 这个过程称为抛出**(throw)**异常。
1.3.1声明异常
在一个方法体中抛出了异常,使用throws通知调用者,让调用者去处理这个异常
public class TestThrow {
public static void main(String[] args) {
try {
divide(); // 调用者处理异常
}catch (InputMismatchException e) {
System.out.println("输入不为整数");
return;
}catch (ArithmeticException e) {
System.out.println("除数不能为0");
System.exit(0);
} catch (Exception e) {
System.out.println("其它异常");
}finally {
System.out.println("有没有异常都会执行,return也会输出,System.exit()不会输出");
}
}
// 声明一个异常 , 调用者去处理
public static void divide() throws Exception{
Scanner input = new Scanner(System.in);
System.out.println("请输入一个整数:");
int num1 = input.nextInt();
System.out.println("请输入除数");
int num2 = input.nextInt();
System.out.println(num1 + "/" + num2 + "=" + num1/num2);
}
}
1.3.2抛出异常
自行抛出的异常
关键字:throw
建议抛出自定义异常,因为这是有语义,便于错误定位
public class TestThrow {
String name;
char gender;
int age;
public TestThrow(String name, char gender, int age) {
super();
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
if ((gender+"").equals("男")||(gender+"").equals("女")) {
this.gender = gender;
}else {
throw new RuntimeException("性别不符合异常");
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >=0 && age <= 200) {
this.age = age;
}else {
throw new RuntimeException("年龄范围不正常");
}
}
@Override
public String toString() {
return "[name=" + name + ", gender=" + gender + ", age=" + age + "]";
}
}
1.4自定义异常
- 需继承Exception或Exception的子类,代表特定问题。
- 异常类型名称望文生义,可在发生特定问题时抛出对应的异常。
常用构造方法:
- 无参数构造方法。
- String message参数的构造方法。
(框架中常用自定义异常)
public class BizException extends RuntimeException{
int code;
String message;
public BizException(int code, String message) {
super();
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
使用
public class TestTh {
public static void main(String[] args) {
try {
Scanner input = new Scanner(System.in);
System.out.println("请输入一个整数:");
int num1 = input.nextInt();
System.out.println("请输入除数");
int num2 = input.nextInt();
System.out.println(num1 + "/" + num2 + "=" + num1/num2);
}catch (InputMismatchException e) {
throw new BizException(1001,"输入不为整数");
}catch (ArithmeticException e) {
throw new BizException(1002,"除数不能为0");
} catch (Exception e) {
throw new BizException(1003,"其它异常");
}
}
}
1.5异常中方法的覆盖
带有异常声明的方法重写:
- 方法名、参数列表、返回值类型必须和父类相同。
- 子类的访问修饰符合父类相同或是比父类更宽。
- 子类中的方法,不能抛出比父类更多、更宽的检查时异常。