信仰:一个人走得远了,就会忘记自己为了什么而出发,希望你可以不忘初心,不要随波逐流,一直走下去
欢迎关注点赞收藏留言
本文由 程序喵正在路上 原创,CSDN首发!
系列专栏:Java从入门到入土
首发时间:2022年7月4日
✅ 如果觉得博主的文章还不错的话,希望小伙伴们三连支持一下哦
如果程序在编译时没有错误信息产生,而在程序运行时出现一些运行时的错误,这样的错误就被称为异常。为了对这样的异常进行处理,Java 提供了异常处理机制。Java 秉承面向对象的基本思想,让所有的异常以类的形式存在。除了内置的异常类之外,Java 也可以自定义异常类。此外,Java 的异常处理机制也允许抛出自定义异常。
在程序设计中,我们必须考虑到可能发生的异常事件,并做出相应的处理,才能保证程序可以正常运行。
下面是几种最常见的异常:
算式异常(ArithmeticException),如程序中包含0做除数的现象。
空指针异常(NullPointerException),没有为对象开辟内存空间而产生的异常。
文件未找到异常(FileNotFoundException)。
Java 中提供了一些异常,用来描述经常发生的错误。对于这些异常,有的需要程序员手动进行捕获、处理或声明抛出,有的则是由 Java 虚拟机自动进行捕获、处理的。
对于可能出现的异常,需要事先预知并进行处理,以保证程序的有效运行,否则程序会出错。对于这些异常,有的需要程序员手动进行捕获处理或声明抛出,称为 “受检查异常”;有的是由 Java 虚拟机自动进行捕获处理的,称为 “运行时异常” 或 “不受检异常”。
Java中常见的异常类如下表所示:
异常类 | 描述 |
---|---|
ArithmeticException | 算术异常类 |
ArrayIndexOutOfBoundsException | 数组下标越界异常类 |
ArrayStoreException | 将与数组类型不兼容的值赋值给数组元素时抛出的异常 |
ClassCastException | 类型强制转换异常类 |
ClassNotFoundException | 未找到相应类异常 |
EOFException | 文件已结束异常类 |
FileNotFoundException | 文件未找到异常类 |
lllegalAccessException | 访问某类被拒绝时抛出的异常 |
InstantiationException | 试图通过 newInstance() 方法创建一个抽象类或抽象接口的实例时抛出该异常 |
IOException | 输入输出异常类 |
NegativeArraySizeException | 建立元素个数为负数的数组异常类 |
NullPointerException | 空指针异常类 |
NumberFormatException | 字符串转换为数字异常类 |
NoSuchFieldException | 字段未找到异常类 |
NoSuchMethodException | 方法未找到异常类 |
SecurityException | 小应用程序(Applet)执行浏览器的安全设置禁止的动作时抛出的异常 |
SQLException | 操作数据库异常类 |
StringlndexOutOfBoundsException | 字符串索引超出范围异常 |
为了保证程序能够有效地执行,需要对发生的异常进行相应的处理。在 Java 中,如果某个方法抛出异常,既可以在当前方法中进行捕捉,处理该异常,也可以将异常向上抛出,由方法调用者来处理。
异常产生后,如果不做任何处理,程序就会被终止。例如,将一个字符串转换为整型数据,可以通过 Integer 类的 parseInt() 方法来实现。但如果该字符串非数字形式,parseInt() 方法就会抛出异常,程序将停留在出现异常的位置,不执行下面的语句。
我们来看一个例子,在项目中创建类 Test,在主方法中实现将字符型数值转换为 int 型。运行程序,系统会报出异常提示。
public class Test {
public static void main(String[] args) {
//定义字符串
String str = "Mike";
//输出提示信息
System.out.println(str + "年龄是:");
//数据类型的转换
int age = Integer.parseInt("20L");
//输出信息
System.out.println(age);
}
}
你觉得输出结果是什么呢?
在本实例中,由于字符串 “20L” 不属于数值类型的字符串,因此在转换为 int 型时发生了 NumberFormatException 异常,如下图所示。
从运行结果中可以看出,在错误语句前面的代码可以正常地运行,而其后的代码却没有被执行。若使用异常处理语句,可以使程序在出现异常后继续执行后面的语句。
Java 语言的异常处理器由 try、catch、finally 这3 个语句块组成。其中,try 语句块存放的是可能发生异常的 Java 语句;catch 程序块在 try 语句块之后,用来激发被捕获的异常;finally 语句块是异常处理结构的最后执行部分,不管 try 块中代码如何退出,都将执行 finally 块。
异常捕获的语法如下。
try {
//程序代码块
}
catch(Exceptiontype1 e) {
//对Exceptiontype1的处理
}
catch(Exceptiontrpe2 e) {
//对Exceptiontype2的处理
}
…
finally {
//程序块
}
通过异常处理器的语法可知,异常处理器大致分为 try-catch 语句块和 finally 语句块。
我们可以对前面例子中的代码进行修改,使用 try-catch 语句块进行处理,如下所示。
public class Test {
public static void main(String[] args) {
//try语句中包含可能出现异常的程序代码
try{
//定义字符串
String str = "Mike";
//输出提示信息
System.out.println(str + "年龄是:");
//数据类型的转换
int age = Integer.parseInt("20L");
//输出信息
System.out.println(age);
} catch(Exception e){ //catch语句块用来获取异常信息
//输出异常性质
System.out.println(e.getMessage());
}
//输出信息
System.out.println("program over");
}
}
从运行结果中我们可以看出,程序可以输出最后的提示信息,没有因为异常而终止。
这是因为我们将可能出现异常的代码用 try-catch 语句块进行处理,当 try 代码块中的语句发生了异常,程序就会跳转到 catch 代码块中执行,执行完 catch 代码块中的程序代码后,继续执行 catch 代码块后的其他代码,而不会执行 try 代码块中发生异常语句后面的代码,由此可以得出,Java 的异常处理是结构化的,不会因为一个异常影响整个程序的执行。
catch 关键字后面的括号中有 Exception 类型的参数 e。Exception 就是 try 代码块传递给 catch 代码块的变量类型,e 就是变量名。
如果你在 catch 括号内写的是 Exception 类型的话,那么 try 语句块中所有类型的异常都会被这个 catch 语句捕获。
我们异常处理经常用下面 3 个函数来获取异常的有关信息:
函数 | 描述 |
---|---|
getMessage() | 输出错误性质 |
toString() | 给出异常的类型与性质 |
printStackTrace() | 指出异常的类型、性质、栈层次及出现在程序中的位置 |
有时我们会忽略掉 catch 语句后的代码,这样,try-catch 语句块就成了一种摆设,一旦程序在运行过程中出现了异常,就会导致最终的运行结果与我们期望的不一致,而错误发生的原因很难查找。因此,开发人员要养成良好的编程习惯,最好在 catch 代码块中编写处理异常的代码。
完整的异常处理语句一定要包含 finally 语句块,不管程序中有无异常发生。一般,不管之前的 try-catch 语句块是否能顺利执行完毕,都会执行 finally 语句块。
在以下 4 种特殊情况下,finally 块不会被执行。
1、在 finally 语句块中发生了异常
2、在前面的代码中用了 System.exit() 退出程序
3、程序所在的线程死亡
4、关闭 CPU
Java 提供了一些内置的异常类来描述经常容易发生的错误,如下表所示。
这些类都继承自 java.lang.Throwable 类。Throwable 类有两个子类:Error 和 Exception,它们分别表示两种异常类型。
Error 类及其子类通常用来描述 Java 运行系统中的内部错误及资源耗尽的错误。Error 类表示的异常比较严重,仅靠修改程序本身是不能恢复执行的,因此被称为致命性类。在大多数情况下,发生该异常时,建议终止程序。
Exception 类称为非致命性类,它代表了另一种异常。发生该异常的程序,可以通过捕获处理后正常运行,保持程序的可读性及可靠性。在开发 Java 程序过程中进行的异常处理,主要就是针对该类及其子类进行的异常处理。对程序中可能发生的该类异常,应该尽可能进行处理,以保证程序能够顺利执行,而不应该在异常发生后终止程序。
Exception 类又根据错误发生的原因分为两种异常类型:RuntimeException 异常和 RuntimeException 之外的异常。
RuntimeException 异常也称为不受检异常,是程序员编写的错误程序导致的,修改了该错误后,程序就可以继续执行。在程序中发生该异常的情况包括除数为 0 的运算、数组下标越界、对没有引用任何对象的变量进行操作等。当 RuntimeExeption 类或其子类所描述的异常发生后,可以不通过 try-catch、throws 语句捕获或抛出,在编译时是可以通过的,只是在运行时由 Java 虚拟机来抛出。
Java 中提供的常见的 RuntimeException 异常如下表所示。这些异常类都是 RuntimeException 类的子类,表示某种具体的不检查异常类型。
异常类 | 描述 |
---|---|
ArithmeticException | 算术异常类 |
ArrayIndexOutOfBoundsException | 数组下标越界异常类 |
ArrayStoreException | 将与数组类型不兼容的值赋值给数组元素时抛出的异常 |
ClassCastException | 类型强制转换异常类 |
IndexOutOfBoundsException | 当某对象(如数组或字符串)的索引超出范围时抛出的异常 |
NegativeArraySizeException | 建立元素个数为负数的数组异常类 |
NullPointerException | 空指针异常类 |
NumberFormatException | 字符串转换为数字异常类 |
SecurityException | 小应用程序(Applet)执行浏览器的安全设置禁止的动作时抛出的异常 |
StringIndexOutOfBoundsException | 字符串索引超出范围异常 |
下面对表中一些常见的不检查异常进行简要介绍。
(1)ArithmeticException类
该类用来描述算术异常,如在除法或求余运算中规定除数不能为 0,所以当除数为 0时,Java 虚拟机抛出该异常,例如:
public class Demo {
public static void main(String[] args) {
int num = 9 % 0; //除数为0,抛出ArithmeticException异常
}
}
(2)NullPointerException类
该类用来描述空指针异常,当引用变量值为 Null,又试图通过 “.” 操作符对其进行访问时,就会抛出该异常,例如:
import java.util.*;
public class Demo {
public static void main(String[] args) {
Date now = null; //声明一个Date型变量now,但不引用任何对象
String today = now.toString(); //试图通过"."操作符进行访问,抛出NullPointerException异常
}
}
(3)NumberFormatException类
该类用来描述字符串转换为数字时的异常。当字符串不是数字格式时,若要将其转换为数字,则抛出该异常,例如:
import java.util.*;
public class Demo {
public static void main(String[] args) {
String s = "24L";
int age = Integer.parseInt(s); //试图将"24L"转换为Int型时,就会抛出NumberFormatException异常
}
}
(4)IndexOutOfBoundsException类
该类用来描述某对象的索引超出范围时的异常,注意,ArrayIndexOutOfBoundsException 类与 StringIndexOutOfBoundsException 类都继承自该类,它们分别用来描述数组下标越界异常和字符串索引超出范围异常。
例如,下面为抛出 ArrayIndexOutOfBoundsException 异常的情况。
int[] a = new int[3]; //定义一个数组
a[3] = 9; //试图对a[3]元素赋值,抛出ArrayIndexOutOfBoundsException异常
下面为抛出 StringIndexOutOfBoundsException 异常的情况。
String name = "ChengZi";
char c = name.charAt(name.length()); //抛出StringIndexOutOfBoundsException异常
(5)ClassCastException类
该类用来描述强制类型转换时的异常,例如,强制转换 String 型为 Integer 型,将抛出该异常。
Object obj = new String("100"); //引用变量obj引用String型对象
Integer num = (Integer) obj; //强制转换obj为Integer类型,抛出ClassCastException异常
RuntimeException 之外的异常用来描述发生的意外的事情。这好比是一个记者根据一个地址去采访一个重要人物,当发生下列情况时,就会抛出该类异常:根据地址没有找到被采访的人或采访被拒绝。该类异常被称为受检查异常(Checked Exception),要求必须通过 try-catch 语句捕获或由 throws 关键字抛出,否则编译出错。
Java 中提供的常见的受检查异常如下表所示,每一个类都表示一种具体的检查异常类型。
异常类 | 描述 |
---|---|
ClassNotFoundException | 未找到相应类时的异常 |
EOFException | 文件已结束异常类 |
FileNotFoundException | 文件未找到异常类 |
IllegalAccessException | 访问某类被拒绝时抛出的异常 |
InstantiationException | 试图通过 newInstance() 方法创建一个抽象类或抽象接口的实例时抛出的异常 |
IOException | 输入输出异常类 |
NoSuchFieldException | 字段未找到异常类 |
NoSuchMethodException | 方法未找到异常类 |
SQLException | 操作数据库异常类 |
使用 Java 内置的异常类可以描述在编程时出现的大部分异常情况,除此之外,用户还可以自定义异常类。用户自定义异常类,只须继承 Exception 类即可。
在程序中使用自定义异常类,大体有以下几个步骤:
● 创建自定义异常类
● 在方法中通过 throw 关键字抛出异常对象
● 如果在当前抛出异常的方法中处理异常,可以使用 try-catch 语句捕获并处理,否则在方法的声明处通过 throws 关键字指明要给方法调用者抛出的异常,继续进行下一步操作
● 在出现异常方法的调用者中捕获并处理异常
在项目中创建 MyException 类,该类继承 Exception,创建自定义异常类实例。
//创建自定义异常类,继承Exception类
public class MyException extends Exception {
//构造方法
public MyException(String ErrorMessage) {
//调用父类构造方法
super(ErrorMessage);
}
}
字符串 ErrorMessage 是要输出的错误信息。若想抛出用户自定义的异常对象,要使用 throw 关键字。
在项目中创建类 Tran,该类中创建一个带有 int 型参数的方法 avg(),该方法用来检查参数是否小于 0 或大于 100。如果参数小于 0 或者大于 100,则通过 throw 关键字抛出一个 MyException 异常对象,并在 main() 方法中捕获该异常。
public class Tran {
//定义方法,抛出异常
static int avg(int num1, int num2) throws MyException {
//判断方法中参数是否满足指定条件
if (num1 < 0 || num2 < 0) {
//抛出错误信息
throw new MyException("不可以使用负数");
}
if (num1 > 100 || num2 > 100) {
throw new MyException("数值太大了");
}
//将参数的平均值返回
return (num1 + num2) / 2;
}
//主方法
public static void main(String[] args) {
try {
//调用avg方法
int result = avg(123, 234);
System.out.println(result);
} catch (MyException e) {
//输出异常信息
System.out.println(e);
}
}
}
如果不想在定义方法时使用 try-catch 语句,可以使用 throws 关键字将异常抛出。
throws 关键字通常被应用在声明方法时,用来指定方法可能抛出的异常。多个异常可使用逗号分隔。
在项目中创建类 Shoot,在该类中创建方法 pop(),在该方法中抛出 NegativeArraySizeException 异常,在主方法中调用该方法,并实现异常处理。
public class Shoot {
static void pop() throws NegativeArraySizeException {
//创建数组
int[] arr = new int[-3];
}
//主方法
public static void main(String[] args) {
try {
//调用pop方法
pop();
} catch (NegativeArraySizeException e) {
System.out.println("pop()方法抛出的异常");
}
}
}
使用 throws 关键字将异常抛给上一级后,如果不想处理该异常,可以继续向上抛出
但最终要有能够处理该异常的代码。
如果是 Error 类、RuntimeException 类或它们的子类,那么可以不使用 throws 关键字说明来声明要抛出的异常,编译仍能顺利通过,但在运行时系统会抛出异常。
throw 关键字通常用于在方法体中抛出一个异常对象。程序在执行到 throw 语句时立即终止,它后面的语句都不执行。通过 throw 抛出异常后,如果想在上一级代码中捕获并处理异常,需要在抛出异常的方法中使用 throws 关键字在方法的声明中指明要抛出的异常。如果要捕捉 throw 抛出的异常,则必须使用 try-catch 语句。
throw 通常用来抛出用户自定义异常。下面我们通过实例来了解 throw 的用法。
在项目中创建类 MyException,继承 Exception,创建自定义异常类。
//创建自定义异常类,继承Exception类
public class MyException extends Exception {
String message;
//构造方法
public MyException(String ErrorMessage) {
message = ErrorMessage;
}
public String getMessage() {
//覆盖getMessage()方法
return message;
}
}
在项目中创建 Captor 类,该类中的 quotient() 方法传递两个 int 型参数,如果其中的一个参数为负数,则会抛出 MyException 异常,最后在 main() 方法中捕获异常。
public class Captor {
static int quotient(int x, int y) throws MyException {
//判断参数是否小于0
if (y < 0) {
//异常信息
throw new MyException("除数不能是负数");
}
return x / y;
}
//主方法
public static void main(String[] args) {
try {
int result = quotient(3, -1);
} catch (MyException e) {
//处理自定义异常
System.out.println(e.getMessage());
} catch (ArithmeticException e) {
//处理ArithmeticException异常
System.out.println("除数不能为0");
} catch (Exception e) {
//处理其他异常
System.out.println("程序发生了其他的异常");
}
}
}
运行结果如下:
在上面的实例中使用了多个 catch 语句来捕获异常。如果调用 quotient(3,-1),将发生 MyException 异常,程序转到 catch (MyException e) 代码块中执行;如果调用 quotient(5,0) 方法,会发生 ArithmeticException 异常,程序转到 catch (ArithmeticException e) 代码块中执行;如果还有其他异常发生,将使用 catch (Exception e) 捕获异常。
由于 Exception 是所有异常类的父类,所以如果将 catch (Exception e) 代码块放在其他两个代码块的前面,后面的代码块将永远得不到执行,就没有什么意义了,所以 catch 语句的顺序不可改变。
Java 异常强制程序员考虑程序的强健性和安全性。异常处理不应用于控制程序的正常流程。异常处理的主要作用是捕获程序在运行时发生的异常并进行相应的处理。编写代码时,处理某个方法可能出现的异常,可遵循以下几条原则。
这次的分享就到这里啦,继续加油哦^^
有出错的地方欢迎在评论区指出来,共同进步,谢谢啦