一、 引入:
不应该出现了一个不算致命的问题就导致整个系统崩溃,所以java设计者提供了一个异常处理机制来解决问题
快速入门:
package exception_;
public class Exception01 {
public static void main(String[] args) {
int num1=10;
int num2=0;
//异常处理流程:把该代码块——》选中——》快捷键:ctrl+alt+t——》选择try-catch
//如果进行异常处理,那么即使出现了异常,程序可以继续执行
try {
int res=num1/num2;
} catch (Exception e) {
throw new RuntimeException("出现异常的原因:"+e.getMessage());//e.getMessage()输出异常信息
}
System.out.println("程序继续运行……");
}
}
//输出:
// Exception in thread "main" java.lang.RuntimeException: 出现异常的原因:/ by zero
// at exception_.Exception01.main(Exception01.java:12)
二、基本介绍:
1、基本概念:java语言中,将程序执行中发生的不正常情况称为“异常”(开发过程中的语法错误和逻辑错误不是异常)
2、执行过程中所发生的异常事件可分为两类:
(1)Error(错误):java虚拟机无法解决的严重问题
如:JVM系统内部错误、资源耗尽等严重情况,比如:StackOverflowError[栈溢出]和OOM(out of memory),Error是严重错误,程序会崩溃
(2)Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理
例如空指针访问,试图读取不存在的文件,网络连接中断等等
Exception分为两大类:运行时异常[ 程序运行时发生的异常 ]和编译时异常[ 编程时编译器检查出的异常 ]
1)运行时异常:编译器检查不出来,编译器不要求强制处置的异常,一般是编程时的逻辑错误,是程序员应该避免其出现的异常,java.lang.RuntimeException类及它的子类都是运行时异常
对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响
2)编译时异常:编译器要求必须处置的异常(任务不合理,就不干活了)
进入到Throwable的源码后,把光标放在 Throwable上,右击,选择……
即可得到……,可以在上面画思维导图(嘿嘿)
右击,选择“显示实现”
即可开始添加
三、异常体系图:
(虚线是实现,实线是继承)
三、详细介绍:
1、常见的运行时异常:
(1)NullPointerException空指针异常
当应用程序试图在需要对象的地方使用null时,抛出该异常
package exception_;
public class NullPointerException_ {
public static void main(String[] args) {
String name=null;
System.out.println(name.length());
}
}
//输出:
// Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
// at exception_.NullPointerException_.main(NullPointerException_.java:6)
(2)ArithmeticException数学运算异常
当出现异常的运算条件时,抛出此异常
package exception_;
public class Exception01 {
public static void main(String[] args) {
int num1=10;
int num2=0;
int res=num1/num2;
System.out.println(res);
}
}
//输出:
// Exception in thread "main" java.lang.ArithmeticException: / by zero
// at exception_.Exception01.main(Exception01.java:7)
(3)ArrayIndexOutOfBoundsException数组下标越界异常
用非法索引访问数组时抛出的异常,如果索引为负或大于等于数组大小,则该索引为非法索引
package exception_;
public class ArrayIndexOutOfBoundsException_ {
public static void main(String[] args) {
int[] arr={1,2,4};
for(int i=0;i<=arr.length;i++){
System.out.println(arr[i]);
}
}
}
//输出:
//1
//2
//4
//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
// at exception_.ArrayIndexOutOfBoundsException_.main(ArrayIndexOutOfBoundsException_.java:7)
(4)ClassCastException类型转换异常
当试图将对象强制转换为不是实例的子类时,抛出该异常
package exception_;
public class ClassCastException_ {
public static void main(String[] args) {
A b1=new B();//向上转型,b1指向A对象
B b2=(B)b1;//向下转型,b1指向B对象
C c2=(C)b1;//b1不能指向C对象,因为B和C没有关系
}
}
class A{}
class B extends A{};
class C extends A{};
//输出:
// Exception in thread "main" java.lang.ClassCastException: class exception_.B cannot be cast to class exception_.C (exception_.B and exception_.C are in unnamed module of loader 'app')
// at exception_.ClassCastException_.main(ClassCastException_.java:7)
(5)NumberFormatException数字格式不正确异常
当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常——》使用异常我们可以确保输入的是满足条件的数字
package exception_;
public class NumberFormatException_ {
public static void main(String[] args) {
String name="韩顺平";//应该输入数字
int num=Integer.parseInt(name);
System.out.println(num);
}
}
//输出:
// Exception in thread "main" java.lang.NumberFormatException: For input string: "韩顺平"
// at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
// at java.base/java.lang.Integer.parseInt(Integer.java:665)
// at java.base/java.lang.Integer.parseInt(Integer.java:781)
// at exception_.NumberFormatException_.main(NumberFormatException_.java:6)
2、常见的编译异常:
(1)SQLException,操作数据时,查询表可能发生异常
(2)IOException,操作文件时,异常
(3)FileNotFoundException,当操作一个不存在的文件时,异常
(4)ClassNotFoundException,加载类,而该类不存在时,异常
(5)EOFException,操作文件,到文件末尾,异常
(6) IllegalArgumentException,参数异常
四、异常处理:
1、异常处理方式:
(1)try-catch-finally(可以没有finally)
1)程序员在代码中捕获发生的异常,自行处理(try用于包含可能出错的代码,catch用于处理try块中发生的异常)
2)
·如果异常发生了,则异常后面的代码不会执行,直接进入到catch块
·如果异常没有发生,则顺序执行try的代码块,不会进入到catch
·如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等),则使用finally
·可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子灰异常在前(因为如果父类在前,就可以囊括后面子类的异常处理,那后面子类异常处理的存在也就没有意义了),如果发生异常,只会匹配一个catch
package exception_;
import project20221109.Person;
public class TryCatchDetail02 {
public static void main(String[] args) {
try {
Person_ person=new Person_();
System.out.println(person.getName());//NullPointerException
int num1=10;
int num2=0;
int res=num1/num2;//ArithmeticException
} catch (NullPointerException e) {
System.out.println("空指针异常="+e.getMessage());
}catch (ArithmeticException e){
System.out.println("算术异常="+e.getMessage());
}catch (Exception e){
System.out.println(e.getMessage());
}finally {
}
}
}
class Person_{
private String name;
public String getName() {
return name;
}
}
//输出:
//null
//算术异常=/ by zero
·可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉 /退出
(应用场景:执行一段代码,不管是否发生异常,都必须执行某个业务逻辑)
package exception_;
public class TryCatchDetail03 {
public static void main(String[] args) {
try {
int n1 = 10;
int n2 = 0;
System.out.println(n1 / n2);
} finally {
System.out.println("执行了finally...");
}
System.out.println("程序继续执行...");
}
}
//输出:
// 执行了finally...
//Exception in thread "main" java.lang.ArithmeticException: / by zero
// at exception_.TryCatchDetail03.main(TryCatchDetail03.java:8)
//练习题
class ExceptionExe01{
public static int method(){
int i=1;
try {
i++;
String[] name=new String[3];
if(name[1].equals("tom")){
System.out.println(name[1]);
}else{
name[3]="hspedu";
}
return 1;
} catch (ArrayIndexOutOfBoundsException e) {
return 2;
}catch (NullPointerException e){
return ++i;
//程序执行到这里时i=3,但不会马上返回,因为还有finally没有执行,
//所以用了一个临时变量temp来保存3
} finally{
++i;
System.out.println("i="+i);
//输出i=4后,因为没有return语句,无法退出程序,又返回上面去返回3
}
}public static void main(String[] args) {
System.out.println(method());
}
}
//输出
//i=4
//3
//题目:如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
//思路:
//1、创建Scanner对象
//2、使用无限循环,去接收一个输入
//3、然后将该输入的值,转成一个int
//4、如果在转换时,抛出异常,说明输入的内容不是一个可以转成int的内容
//5、如果没有抛出异常,则break该循环
package exception_;
import java.util.Scanner;
public class TryCatchDetail04 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int num=0;
String inputStr="";
while(true){
System.out.println("请输入一个整数:");
inputStr=scanner.next();
try {
num=Integer.parseInt(inputStr);//这里可能抛出异常k
break;
} catch (NumberFormatException e) {
System.out.println("你输入的不是一个整数:");
}
}
System.out.println("你输入的值是="+num);
}
}
//输出:
//请输入一个整数:
//tom
//你输入的不是一个整数:
//请输入一个整数:
//1
//你输入的值是=1
(2)throws
1)将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM
如果程序员没有显示是处理异常,则默认是throws
2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类
public void f2() throws FileNotFoundException,NullPointerException,ArithmeticException{}
//也可以写成
public void f2() throws Exception{}
3)子类重写父类的方法时,对抛出异常的规定:
子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型(如果子类抛出的异常比父类大,那子类抛完到父类抛出异常时就没有必要抛了)
class Father{
public void method() throws RuntimeException{}
}
class Son extends Father{
public void method() throws ArithmeticException{}
}
4)在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws
5)细节:
public static void f1(){
f3();
//报错原因:因为f3()方法抛出的是一个编译异常,即这时f1()必须处理这个编译异常
//方法一:public static void f1() throws FileNotFoundException{}
//方法二:
// try {
// f3();
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
}
public static void f3() throws FileNotFoundException{
FileInputStream fis=new FileInputStream("d://aa.txt");
}
public static void f1(){
f3();//因为f3()抛出的是运行异常,不要求程序员显示处理,因为有默认处理机制
}
public static void f3() throws ArithmeticException{
}
五、自定义异常
1、概念:当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这时可以自己设计异常类,用于描述该错误信息
2、步骤:
(1)定义类:自己写类名,继承Exception或RuntimeException
(2)如果继承Exception,属于编译异常
(3)如果继承RuntimeException,属于运行异常(一般是继承RuntimeException),好处在于可以使用默认的处理机制
六、throw 和 throws的区别:
七、练习题
package exception_;
import java.util.Scanner;
public class Homework01 {
public static void main(String[] args) {
try {
if(args.length!=2){
throw new ArrayIndexOutOfBoundsException("参数个数不对");
}
int n1=Integer.parseInt(args[0]);
int n2=Integer.parseInt(args[1]);
double res=cal(n1,n2);
System.out.println("计算结果是:"+res);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());
} catch (NumberFormatException e) {
System.out.println("参数格式不正确,需要输出整数");;
}catch (ArithmeticException e){
System.out.println("出现了除0的异常");
}
}
public static double cal(int n1,int n2){
return n1/n2;
}
}
//在编辑配置处输入