JavaSE01_Day05(中)-异常(throws关键字、自定义异常)
一、异常
1.1 throws关键字
在计算机编程中,会设计很多的业务方法,不同的方法一般情况下会代表着一个功能,如果这个方法在进行书写相关业务逻辑的时候,可能有需要进行处理的异常需要抛出,但是这个方法希望调用者在进行调用的过程中进行处理,而不是在定义的时候就进行处理,此时可以在方法的后方使用throws关键字抛出相关的异常类型,最终由调用者进行对该异常处理。
package cn.tedu.execption;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* throws关键字使用案例
* @author cjn
*
*/
public class ThrowsDemo {
public static void main(String[] args) {
/*
* 调用createIO方法
* 当在main方法中调用了createIO方法时,
* 1.由于方法后方抛出了IOException异常,
* 那么最终哪里调用这个方法,哪里就需要对该方法
* 所出现的异常进行处理。
* 2.如果在main方法中进行调用时,不建议在main方法后方
* 继续使用throws关键字,抛出相关异常。
* 原因是:当抛出以后,如果程序出错,最终的错误是抛给了
* Java虚拟机(JVM),虚拟机没有处理异常的能力,
* 最终还会导致程序的瘫痪。
*3.建议在调用处使用try-catch进行异常的捕获处理
*/
try {
createIO();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
//查看简单的错误信息
System.out.println(e.getMessage());
}
System.out.println("程序执行完毕");
}
/**
* 该方法的作用是创建一个输出流对象,写出数据.
* 方法内部没有对异常进行捕获处理,而是希望调用方处理
* @throws IOException
*/
public static void createIO() throws IOException {
//创建文件输出流(低级流)对象
FileOutputStream fos = new FileOutputStream("fos.txt");
//写出整数数据
fos.write(97);
//关闭资源
fos.close();
}
}
在定义方法以后,方法中的逻辑如果可能会出现非受检异常(运行时异常时),当调用方调用这个方法时,其实并不会检测出有异常需要进行处理,那么可以凭借着经验,在自己知道可能会发生异常的情况进行使用try-catch捕获处理,如果说不知道还有哪些非受检异常时,可以不加try。这个案例在书写时,方法后方添加throws关键字抛出相关的非受检异常的原因是想带着大家查看,这种情况下,调用方调用该方法仍然不会有编译报错。
package cn.tedu.execption;
/**
* throws关键字对运行时异常的案例演示
* @author cjn
*
*/
public class ThrowsDemo02 {
public static void main(String[] args) {
String[] strs = {"123","456","789"};
//运行时异常不属受检异常,所以在调用该方法时不会有编译报错
try {
getArrayElement(strs);
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println(e.getMessage());
} catch (NullPointerException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("程序结束");
}
/**
* 获取字符串数组中所有的元素内容
* strs.length可能出现空指针异常
* 遍历的时候取了等号的情况可能会出数组下标越界异常
*/
public static String getArrayElement(String[] strs)
throws ArrayIndexOutOfBoundsException,NullPointerException{
String string = "";
for (int i = 0; i <= strs.length; i++) {
string = strs[i];
}
return string;
}
}
1.2 被throws关键字抛出异常的方法被重写的情况说明:
当前这种情况,需要有一个前提条件,这个条件就是存在两个类,类与类之间需要存在继承关系,当超类的某个方法后方使用throws关键字抛出了相关的异常,在派生类对于超类的该方法进行重写时需要满足如下规则:
-
超类中方法后面抛出什么异常,派生类在重写该方法时原样书写
-
超类中方法后面抛出的异常,在派生类重写该方法时不添加throws关键字抛出异常
-
可以在重写超类中的方法时,抛出超类的方法的部分异常
-
如果在超类的方法后方比如抛出了IOException异常,那么可以在派生类重写方法时,在方法的后方抛出IOException异常的派生类异常
重写时不能操作的:
-
重写超类中方法时,派生类方法后方使用throws关键字抛出了和超类方法不相干的其他异常
-
重写超类中方法时,派生类方法后方使用throws关键字抛出的异常时派生类重写方法的超类异常
package cn.tedu.execption;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
/**
* 重写派生类中方法带有throws关键字的方法时注意事项案例
* @author cjn
*
*/
public class ThrowsDemo03 {
public static void main(String[] args) {
}
}
/**
* 外部派生类
* @author cjn
*
*/
class Son extends Father{
//public void doSome() throws IOException,ClassCastException{
//和超类中被重写的方法,所抛出的异常一摸一样,允许
//}
//public void doSome() throws FileNotFoundException,ClassCastException {
//和超类中被重写的方法,所抛出的异常是派生类异常,允许
//}
//public void doSome() {
//重写超类方法时,后面抛出的异常取消,允许
//}
//public void doSome() throws ClassCastException{
//重写超类方法时,抛出超类方法的部分异常
//}
//public void doSome() throws SQLException,ClassCastException{
//重写超类方法时,throws后面跟的异常,和超类方法的异常没有任何的关系,不允许
//}
//public void doSome() throws Exception{
//重写超类方法时,throws后面跟的异常,是超类方法抛出异常的超类,不允许
//}
}
/**
* 外部类超类
* @author cjn
*/
class Father {
public void doSome() throws IOException,ClassCastException{
//方法体逻辑略
}
}
1.3 自定义异常
其实在JDK中提供了很多的异常类,可以满足项目中的使用,但是如果从业务的严谨性来说,假设有一个Person类,类中有age年龄属性,如果创建Person实例时,在对一个人的对象的年龄属性进行赋值时,如果赋值-1岁,或者300岁,这是与实际的业务场景不吻合的,也就会导致程序的健壮性不好。所以需要使用自定义异常满足项目的实际业务要求。
语法结构:
public class [自定义异常类型] extends Exception{
//1.自定义异常类需要继承异常超类
//2.生成自定义异常类的构造器,需要去选择调用超类中的构造器内容
}
案例演示:
package cn.tedu.execption_two;
/**
* 自定义一个年龄不合乎实际业务的异常类
* @author cjn
*
*/
//要继承Exception异常超类
public class AgeCustomExecption extends Exception{
//要添加序列版本号
private static final long serialVersionUID = 1L;
//下面的利用工具自动生成:Generate Constructors from SuperClass
public AgeCustomExecption() {
super();
}
public AgeCustomExecption(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public AgeCustomExecption(String message, Throwable cause) {
super(message, cause);
}
public AgeCustomExecption(String message) {
super(message);
}
public AgeCustomExecption(Throwable cause) {
super(cause);
}
}
package cn.tedu.execption_two;
/**
* 自定义Person类
* @author cjn
*
*/
public class Person {
private String name;
private int age;
private String gender;
//定义无参构造,减少报错
public Person() {}
public Person(String name, int age, String gender) {
super();
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
//对年龄出现不合理的情况进行抛出异常处理
public void setAge(int age) throws AgeCustomExecption{
//不合理的年龄赋值情况
if (age<0 || age>200) {
//抛出自定义异常,关键字throw 创建自定义异常对象
throw new AgeCustomExecption("年龄赋值不合法!!!");
}
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}