Java异常概念
异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。
从广义上讲,异常指一切不正常的情况。包括Error和Exception
Java程序在执行过程中所发生的异常(运行时一切不正常情况)事件可分为两类:
-
Error错误:指的是通过程序无法解决的,Java虚拟机无法解决的严重问题。一般不编写针对性的代码进行处理。
eg.内存不够用、JVM系统内部错误、资源耗尽
int[] a = new int[Integer.MAX_VALUE]; //OutOfMemoryError Demo1.test(); //栈溢出错误 StackOverflowError Demo1.test1(1000000); //栈溢出错误 StackOverflowError } public static void test(){ test(); } public static void test1(int n ){ if(n==1){ return; } test1(n-1); }
-
Exception异常:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。
eg. 访问数组下标越界、试图读取不存在的文件、网络连接中断
异常的一些案例:
java中把语法中会出现的问题,都包装成一个类,当程序中出现此类问题时,抛出此类的对象。
java默认情况下,如果出现了异常,那么久简单粗暴地抛出异常信息,然后终止程序运行。
int a = 10;
int b = 0;
/*
异常的类型(何种情况下出现):异常的原因
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Demo2.main(Demo2.java:8) 异常的位置
*/
System.out.println(a/b); //算数异常
System.out.println("后面的代码");
int[] a = new int[5];
a[5] = 10;
/* 数组越界
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at Demo2.main(Demo2.java:19)*/
Object s = 100;
String s1 = (String) s;
/* 类转换异常
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Demo2.main(Demo2.java:26)*/
String s = null;
s.length(); //编译看左边,运行看右边
/* 空指针异常
Exception in thread "main" java.lang.NullPointerException
at Demo2.main(Demo2.java:33)
*/
Integer a = new Integer("1a0");
/* 数字格式化异常
Exception in thread "main" java.lang.NumberFormatException: For input string: "1a0"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.<init>(Integer.java:867)
at Demo2.main(Demo2.java:39)
*/
异常的体系结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ho0JRExr-1643032300293)(E:\Java学习\2022-1-24java第五章常用类4_第六章异常\课件\异常体系.png)]
Throwable
-
Error
-
Exception
分成两大类:
- 运行时异常 继承自RuntimeException的异常类,编译时可以不处理,根据经验判断
- 检查异常(编译期异常 写代码时就要强制处理)
异常处理
在编写代码时,预计程序中可能出现的问题,针对问题进行捕获处理。
程序正常执行,如果没有问题,按照正常的流程执行,如果有异常,按照事先定义的处理流程执行。
try、catch
try{
可能出现异常的代码
}catch(具体的异常类型 形参){
对给定类型的异常进行处理
}
后续程序执行
捕获异常的有关信息:与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。
-
getMessage() 获取异常信息,返回字符串
-
printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
int a = 10;
int b = 0;
try {
int c = a/b; //算数异常
}catch (ArithmeticException ae){
System.out.println("算数运算异常");
}
System.out.println("后面的程序继续执行");
一个try可以对应多个catch
int a = 10;
int b = 2;
try {
int c = a/b; //正常执行
//第二个catch处理
String s = null;
s.length();
}catch (ArithmeticException ae){
System.out.println("算数运算异常");
}catch (NullPointerException ne){
System.out.println("对象不能为空");
}
System.out.println("后面的程序继续执行");
/*
对象不能为空
后面的程序继续执行
*/
int a = 10;
int b = 2;
try {
int c = a/b; //正常运行
//第三个catch处理
String s = "a";
s.length();
new Integer("a"); //NumberFormatException
}catch (ArithmeticException ae){
System.out.println("算数运算异常");
}catch (NullPointerException ne){
System.out.println("对象不能为空");
}catch (Exception e){ //多态 大类型必须写在下面,小的类型、精确的类型写在上面
e.printStackTrace(); //开发期间使用此方法,向控制台打印输出日志信息,后期通过日志组件输出信息到文件中
System.out.println(e.getMessage());//异常原因
System.out.println("系统忙,请稍后再试");
}
System.out.println("后面的程序继续执行");
/*输出结果
java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.<init>(Integer.java:867)
at com.ffyc.javaexception.Demo3.main(Demo3.java:24)
For input string: "a"
系统忙,请稍后再试
后面的程序继续执行
*/
注意:try中代码若是遇到异常后面的代码概不执行,catch只为应对try中遇到的各种问题。
int a = 10;
int b = 0;
try {
//第一个catch处理
int c = a/b; //算数运算异常
//直接不执行,默认也出现异常
String s = "a";
s.length();
new Integer("a"); //NumberFormatException
}catch (ArithmeticException ae){
System.out.println("算数运算异常");
}catch (NullPointerException ne){
System.out.println("对象不能为空");
}catch (Exception e){ //多态 大类型必须写在下面,小的类型、精确的类型写在上面
e.printStackTrace(); //开发期间使用此方法,向控制台打印输出日志信息,后期通过日志组件输出信息到文件中
System.out.println(e.getMessage());//异常原因
System.out.println("系统忙,请稍后再试");
}
System.out.println("后面的程序继续执行");
/*输出结果
算数运算异常
后面的程序继续执行
*/
finally
try{
可能出现异常的代码
}catch(具体的异常类型 形参){
对给定类型的异常进行处理
}finally{
此代码块一定会执行,即使出现异常
将一些必须要执行的逻辑写在此finally代码块中
}
public static void main(String[] args) {
System.out.println(Demo4.test(10, 0));
}
public static int test(int a,int b){
try {
int c = a/b;
return c;
}catch (Exception e){
System.out.println("程序出错");
return -1; //假设出现异常返回-1
}finally { //无论程序异常与否,都要执行
System.out.println("关闭连接");
}
}
/*运行结果:
程序出错
关闭连接
-1
*/
后面讲,出现异常,执行必须的逻辑,并没有处理异常
try{
}finally{
}
throws
定义一个方法的时候,可以使用throws关键字声明,表示此方法不处理异常,而交给方法调用处进行处理。
-
任何方法都可以使用throws关键字声明异常类型,包括抽象方法。
-
子类重写父类中的方法,子类方法不能声明抛出比父类类型更大的异常(针对编 译期异常)。
-
使用了throws的方法,调用时必须处理声明的异常,要么使用try-catch,要么继续使用throws声明。
声明方法可能会出现某种异常,谁调用谁就需要进行处理。处理:可以继续throws,或者try{} catch(){}
此处的不处理,指的是不使用try{}catch(){}处理异常
public static void main(String[] args) {
try { //在顶级方法中,处理异常
Demo5.test1(); //异常导致连锁异常
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println("后续代码"); //若不处理异常,则无法执行
}
//一般在偏底层的方法中不处理异常,只声明,在顶级的方法处处理异常
public static void test1() throws UnsupportedEncodingException {
System.out.println("test1");
Demo5.test2(); //异常导致连锁异常
}
/*
throws在方法声明处,声明此方法可能会出现某种异常类型。
throws后多加编译期异常
如果抛出throws ArithmeticException是运行时异常,那么调用的地方可以处理也可以不处理
UnsupportedEncodingException是属于编译期异常(检查异常),那么谁调用此方法必须在编译期间就进行处理(try catch或throws)
*/
// 运行时异常 编译期异常
public static void test2() throws ArithmeticException, UnsupportedEncodingException {
System.out.println("test2");
"abc".getBytes("utf-8"); //UnsupportedEncodingException
System.out.println(10/0); //异常
}
throw
在程序中主动抛出异常对象,表示此方法出现了某种异常。
public static void main(String[] args) {
try {
checkScore(110);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static char checkScore(int score) throws Exception {
if(score<0 || score>100){
//主动在程序中使用throws关键字抛出异常对象
throw new Exception("无效分数");
}
if(score>=90){
return 'A'; //只能返回char类型
}else {
return 'B';
}
}
throws和throw
throw用于方法体中,用来抛出一个实际的异常对象,使用throw后,要么使用try catch捕获异常,要么使用throws声明异常。
throws用于方法声明处,用来声明该方法可能发生的异常类型,可以是多个异常类型,用来强制调用该方法时处理这些异常。
抽象方法也可以使用throws。
自定义异常
主要是对程序中的业务逻辑出现不满足情况时抛出。
基本语法:
public class 异常类名 extends Exception/RuntimeException{
public 异常类名(String msg){
super(msg);
}
}
自定义异常类中往往不写其他方法,只重载需要使用的构造方法。
继承Exception,在方法中使用throw抛出后,必须在方法中try-catch或throws抛出。
public class Demo7 {
public static void main(String[] args) {
try {
checkScore(110);
} catch (ScoreException e) {
System.out.println(e.getMessage());
}
}
public static char checkScore(int score) throws ScoreException {
if(score<0 || score>100){
//主动在程序中使用throws关键字抛出异常对象
throw new ScoreException("无效分数");
}
if(score>=90){
return 'A'; //只能返回char类型
}else {
return 'B';
}
}
}
/**
当不满足百分制分数时抛出此类对象
*/
public class ScoreException extends Exception{
public ScoreException(String message) {
super(message);
}
}
{
//主动在程序中使用throws关键字抛出异常对象
throw new ScoreException(“无效分数”);
}
if(score>=90){
return ‘A’; //只能返回char类型
}else {
return ‘B’;
}
}
}
/**
当不满足百分制分数时抛出此类对象
*/
public class ScoreException extends Exception{
public ScoreException(String message) {
super(message);
}
}