为什么要有throw和throws:
首先,有个public修饰的成员变量age:
public class Student {
private int age;
}
这时,age有个缺点:在其他类调用age时,age的范围无法控制,如果我们想要控制范围,此时,用到了封装:
Student.java
public class Student {
private int age;
public void setAge(int age) throws AgeException {
if (age > 1 && age < 20) {
this.age = age;
} else {
System.out.println("年龄范围不符合...");
}
}
public int getAge() {
return age;
}
}
Work.java
public class Work {
public static void main(String[] args) {
Student student = new Student();
student.setAge(50);
System.out.println(student.getAge());
}
}
输出:
年龄范围不符合…
但此时,仍然存在一个缺点,编写Test类的程序员并不能发现错在哪里,应该怎么改,这时,就用到了throw。
throw关键字:
此时,把Student类进行修改:
public class Student {
private int age;
public void setAge(int age) throws AgeException {
if (age > 1 && age < 20) {
this.age = age;
} else {
throw new NullPointerException("年龄范围不符合..."); //将System输出语句改为throw语句。
}
}
public int getAge() {
return age;
}
}
此时运行Work.java,输出为:
Exception in thread “main” java.lang.NullPointerException: 年龄范围不符合…
at afternoon.Student.setAge(Student.java:12)
at afternoon.Work.main(Work.java:9)
此时点击Student.java:12,可以直接找到throw语句,从而了解哪里出错,进而点击Work.java:9,可以直接回到出错的student.setAge(50);语句,从而快速修改。但是throw语句中的NullPointerException指的是空指针异常,与age的超出范围意思相差太大,如果有一个AgeException为名的异常更能表达错在哪里。于是,就有了自定义异常。
自定义异常:
应该怎么做?先观察自带的异常(鼠标选中想观察的异常+Ctri键就会出来该源码):
通过观察可以发现,创建自定义异常只需要以下两点:
1、创建继承Exception 或其子类的自定义类;
2、自定义异常类调用父类构造函数(通常是含有一个String类型参数的构造函数);
此时还少了 private static final long serialVersionUID ,将鼠标放在有黄线的AgeException,选择第二个Add generated serial version ID就完成了自定义异常。
注意:现在继承的是运行时异常。
代码如下:
public class AgeException extends RuntimeException {
private static final long serialVersionUID = -1337582885342407212L;
public AgeException(String message) {
super(message);
}
}
抛出异常:
1、运行时异常:
此时,Student类代码可以写为:
Student.java
public class Student {
private int age;
public void setAge(int age) throws AgeException {
if (age > 1 && age < 20) {
this.age = age;
} else {
throw new AgeException("年龄范围不符合..."); //用了AgeException。
}
}
public int getAge() {
return age;
}
}
Work.java输出:
Exception in thread “main” exception.AgeException: 年龄范围不符合…
at afternoon.Student.setAge(Student.java:12)
at afternoon.Work.main(Work.java:6)
这样写之后,问题又来了,只是知道了有异常和在哪,但是这个异常依然存在,怎么处理?此时,用到了抛出异常。
① 将异常抛给自己:
Student.java
public class Student {
private int age;
public void setAge(int age) throws AgeException {
if (age > 1 && age < 20) {
this.age = age;
} else {
try { //利用try—catch语句将异常抛给自己。
throw new AgeException("年龄范围不符合...");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public int getAge() {
return age;
}
}
此时,异常抛出后直接使用try-catch进行处理,异常在Student类中得到解决,在Work类中仅仅为提醒作用,所以不经常使用。
② 将异常抛给方法调用者:
(1)如果两个类都不加try-catch进行处理,此时仅仅使用throw关键字将异常对象抛出,此处没做任何处理,本方法中后续的代码将失效。
(2)当Work类中运用try-catch进行处理时,代码如下:
import exception.AgeException;
public class Work {
public static void main(String[] args) {
Student student = new Student();
try {
student.setAge(50);
} catch (AgeException e) {
e.printStackTrace();
}
System.out.println(student.getAge());
}
}
方法调用者使用try-catch处理该异常,不会影响本方法中后续代码的运行。
总结:
异常对象为运行时,则方法参数列表后面可以不使用throws,也可以将异常抛给方法调用者,用不用try-catch处理都可以进行编译。
2、检查时异常:
让AgeException继承Exception,此时AgeException为检查时异常。
① 将异常抛给自己:此时与运行时异常一样。
② 将异常抛给方法调用者:
不能直接用throw new AgeException(“年龄范围不符合…”); ,还需要使用throws抛出抛出创建该异常对象的异常类或其父类,参见备注示例代码:
Student.java
public void setAge(int age) throws AgeException { //使用throws。
if (age > 1 && age < 20) {
this.age = age;
} else {
throw new AgeException("年龄范围不符合...");
}
}
此时,Work.java中调用该方法的语句也必须使用try-catch处理该异常,不用会报错,不能编译:
Work.java
import exception.AgeException;
public class Work {
public static void main(String[] args) {
Student student = new Student();
try {
student.setAge(50);
} catch (AgeException e) {
e.printStackTrace();
}
System.out.println(student.getAge());
}
}
总结:
1、当方法体中的throw关键字抛出由检查时异常创建的对象时,如果该异常对象在抛出的同时已经通过try-catch进行了处理,则可以不使用throws,否则必须使用throws抛出创建该对象的异常类或其父类。
2、所调用的方法抛出了检查时异常时,如果该方法在调用的同时已经通过try-catch进行了处理,则可以不使用throws继续上抛该异常,否则必须使用throws才能上抛该异常,此时上抛的异常类可以是调用方法时方法抛出的异常类也可以是其父类。
throw与throws的区别:
1、抛出的东西不同:throw抛出的是具体的异常对象,而throws抛出的是抽象的异常类。
2、使用位置不同:throw一般用在方法体中,也可用在代码块中,但是如果抛出的是检查时异常类创建的对象,则必须使用try-catch自行处理;throws只能用在方法声明括号后面。