异常处理
在程序设计和运行过程中,发生错误是不可避免的。为此,Java提供了异常处理机制来帮助编程者检查可能出现的错误,保证程序的可读性和可维护性。Java将异常封装到一个类中,出现错误时,就会抛出异常。
在程序中,错误可能产生于编程者没有预料到的各种情况,或者是超出了可控范围的环境因素,比如用户的坏数据、试图打开不存在的文件,空指针,数组溢出等等异常。异常在Java语言中也是作为类的实例形式出现的。当某一方法发生错误时,这个方法会创建一个对象,并传递给正在运行的系统。这个对象就是异常对象。通过异常处理机制,可以将非正常情况下的处理代码与程序的主逻辑分离,即在编写代码主流程的同时在其他地方处理异常。
在Java中,如果某个方法抛出异常,既可以在当前方法中进行捕获,然后处理异常;也可以将异常向上抛出,由方法调用者来处理。
捕捉异常
异常捕获结构由try、catch、finally3部分组成。
try语句块中存放的是可能发生异常的Java语句;
catch语句块在try之后,用来激发被捕获的异常;
finally语句块是异常处理结构的随后执行部分,无论try语句中的代码如何退出,最终都会执行finally语句块。
public class Take {
public static void main(String[] args) {
try {
String str = "lili";
System.out.println(str + "年龄是:");
int age = Integer.parseInt("20L");
System.out.println(age);
}catch(Exception e) {
e.printStackTrace();
}
System.out.println("program over");
}
}
运行结果:
lili年龄是:
java.lang.NumberFormatException: For input string: "20L"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at com.jcy.Take.main(Take.java:9)
program over
从结果中看,程序依然会输出异常信息,没有因为异常而终止。在代码中将可能出现的异常用try-catch语句块进行了处理,当try代码块中的局域发生异常时,程序会跳转到catch中执行,执行完成后继续执行后面代码,而不会停止运行。
☆Exception是try传递给catch的变量类型,e是变量名。catch中的e.printStackTrace用于输出错误性质。通常情况下,有三种函数可用于获取异常的相关信息:
getMessage():输出错误性质
toString():给出异常的类型与性质
printStackTrace():指出异常的类型、性质、栈层次及出现在程序中的位置。
题目:创建类Number,通过类中的方法count可得到任意两个数相乘的结果,并在调用该方法的主方法中使用try-catch语句捕捉可能发生的异常。
/*
* @author jiacy
* @date 2020-2-9
* @version V1.0
* 模拟除数为0的异常,查看系统报出的异常
*/
public class Number {
public static int count(int m , int n) {
return m * n;
}
public static void main(String[] args) {
try {
int result = count(1000,1/0);
System.out.println(result);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
运行结果:
java.lang.ArithmeticException: / by zero //除数为0异常
at com.jcy.Number.main(Number.java:14)
常见异常
以下为Java中提供的常用语描述发生的错误的异常类。
异常类 | 说明 |
ClassCastException | 类型转换异常 |
ClassNotFoundException | 未找到相应类异常 |
ArithmeticException | 算术异常 |
ArrayIndexOutOfBoundsException | 数组下标越界异常 |
ArrayStoreException | 数组中包含不兼容的值抛出的异常 |
SQLException | 操作数据库异常类 |
NullPointerException | 空指针异常 |
NoSuchFieldException | 字段未找到异常 |
NoSuchmethodException | 方法未找到抛出的异常 |
NumberFormatException | 字符串转换为数字抛出的异常 |
NegativeArraySizeException | 数组元素个数为负数抛出的异常 |
StringIndexOutOfBoundsException | 字符串索引超出范围抛出的异常 |
IOException | 输入输出异常 |
IllegalAccessException | 不允许访问某类异常 |
InstantiationException | 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常 |
EOFException | 文件已结束异常 |
FileNotFoundException | 文件未找到异常 |
自定义异常
通过上述的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户只需继Exception类即可自定义异常。
使用自定义异常类大致可分为以下几个步骤:
1)创建自定义异常类
2)在方法中通过throw关键字抛出异常对象
3)如果在当前抛出的方法中处理异常,可以使用try-catch语句块捕获并处理,否则在方法声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作
4)在出现异常方法的调用者中捕获并处理异常
throw关键字通常用于方法体中,并抛出一个异常对象。程序在运行到throw时立即终止,后面的语句不再执行。
举例:
1)先定义自定义异常MyException
public class MyException extends Exception{ //创建自定义异常类
String message; //定义String类型变量
public MyException(String ErrorMessagr) { //父类方法
message = ErrorMessagr;
}
public String getMessage() { //覆盖getMessage()方法
return message;
}
}
2)使用throw关键字捕捉异常
public class Captor { //创建类
static int quotient(int x ,int y) throws MyException{ //定义方法抛出异常
if(y<0) { //判断参数是否小于0
throw new MyException("除数不能是负数"); //异常信息
}
return x / y; //返回值
}
public static void main(String[] args) { //主方法
try { //在try语句中加入可能发生异常的语句
int result = quotient(3,-1); //调用方法quotient()
}catch(MyException e) { //处理自定义异常
System.out.println(e.getMessage()); //输出异常信息
}catch(ArithmeticException e) { //处理ArithmeticException异常
System.out.println("除数不能为0"); //输出异常信息
}catch(Exception e) { //处理其他异常
System.out.println("程序发生了其他异常"); //输出异常信息
}
}
}
输出结果:
除数不能是负数
题目:编写一个异常类MyException,再编写一个类Student,该类有一个产生异常的方法speak(int m),要求参数m的值大于1000时,方法抛出一个MyException对象。最后编写主类,在主方法中创建Student对象,让该对象调用speak()方法。
编写异常类MyException
package exercise12;
public class MyException extends Exception{
public MyException(String ErrorMassage) {
super(ErrorMassage);
}
}
编写类Student
package exercise12;
public class Student {
static void speak(int m)throws MyException{
if(m > 1000) {
throw new MyException("数值太大了!");
}
}
}
编写主类
package exercise12;
public class Sl1209 {
public static void main(String[] args) {
Student stu = new Student();
try {
stu.speak(2000);
}catch(MyException e) {
e.printStackTrace(); //指出异常的类型、性质、栈层次及出现在程序中的位置。
}
}
}
运行结果:
exercise12.MyException: 数值太大了! //类Student中定义的异常抛出
at exercise12.Student.speak(Student.java:6)//调用查看的异常信息
at exercise12.Sl1209.main(Sl1209.java:8)
异常的使用原则
Java异常强制用户去考虑程序的健壮性和安全性。异常处理不应用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应的处理。
对于编写代码处理过程中出现的异常,可遵循如下原则:
1)在当前方法声明中使用try-catch语句捕获异常;
2)一个方法被覆盖时,覆盖它的方法必须抛出相同异常或其子类;
3)如果父类抛出多个异常,则覆盖方法必须抛出异常的一个子集,不能抛出新的异常。