首先写一个一般的封装程序代码,用直接输出来判断给定的数据是否异常:
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setAge(100);
System.out.println(student.getAge());
}
}
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0 || age>15) {
System.out.println("年龄要在0-15之间");
}else {
this.age = age;
}
}
}
但此时单纯的输出根本无法定位程序哪个地方出现了问题,故我们会使用throw来抛出一个异常对象。
throw关键字
throw用于抛出具体异常类的对象,一般用于方法体中。
当所写的代码因不满足某些条件致使程序无法运行时可以借助throw抛出一个异常对象提醒程序员。
当该异常为运行时异常时:
1、抛出异常给调用者:
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0 || age>15) {
throw new NullPointerException("年龄要在0-15之间");//抛出一个运行时异常给调用者
}else {
this.age = age;
}
}
}
(1)此时调用者可以用try-catch语句捕获异常:
public class Test {
public static void main(String[] args) {
Student student = new Student();
try {
student.setAge(100);
} catch (Exception e) {
e.printStackTrace();
}//通过try-catch语句进行捕获
System.out.println(student.getAge());
}
}
(2)调用者也可以继续上抛该异常(由于方法抛出的是运行时异常类创建的对象,所以可以如下这样做;如果抛出由检查时异常类创建的对象,则这种处理方式必须使用throws关键字抛出创建该对象的异常类或其父类)
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setAge(100);//这样写可以继续把异常上抛
System.out.println(student.getAge());
}
}
2、抛出异常后直接自己解决:
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0 || age>15) {
try {
throw new NullPointerException("年龄要在0-15之间");
} catch (NullPointerException e) {
e.printStackTrace();
}//异常抛出后直接使用try-catch自己进行处理
}else {
this.age = age;
}
}
}
此时调用者便不需要在接受异常:
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setAge(100);//这样写可以继续把异常上抛
System.out.println(student.getAge());
}
}
throw关键字一般用在方法体中,也可以用在代码块中,但如果代码块中抛出的异常对象是由检查时异常创建的,则必须使用try-catch进行处理
运行时异常:
public class Test1 {
int a=9;
int b=0;
{
if(b==0) {
throw new RuntimeException("分母不能为0");//运行时异常可直接抛出
/*try {
throw new RuntimeException("分母不能为0");
} catch (Exception e) {
e.printStackTrace();
}*/ //也可以用try-catch捕获
}
System.out.println(a/b);
}
public static void main(String[] args) /*throws Exception*/ {
new Test1();
}
}
检查时异常:
public class Test1 {
int a=9;
int b=0;
{
if(b==0) {
try {
throw new Exception("分母不能为0");
} catch (Exception e) {
e.printStackTrace();
}
}//由于代码块不能写throws,故检查时异常必须用try-catch进行捕获
System.out.println(a/b);
}
public static void main(String[] args) {
new Test1();
}
}
当使用throw抛出异常对象时没有用try-catch捕获该异常对象,则该抛出异常对象语句执行后其所在方法就直接结束执行,即throw后不能直接跟代码。(类似于return)
public class Test1 {
public static void main(String[] args) {
int age = 1200;
throw new RuntimeException("年龄无效");//单独throw后面不允许直接跟代码,否则会报错
System.out.println(age);//此时会报错
}
}
public class Test1 {
public static void main(String[] args) {
int age = 1200;
if(age>120||age<0) {
throw new RuntimeException("年龄无效");
}
System.out.println(age);//此时虽然没有报错,只是因为throw放到了if语句块中,但此语句仍然不会执行
}
}
throws关键字
throws用于声明方法可能抛出的异常,其后为异常类,可以有多个,异常类之间用英文逗号间隔。
1、当方法体中的throw关键字抛出由检查时异常创建的对象时,如果该异常对象在抛出的同时已经通过try-catch进行了处理,则可以不使用throws,否则必须使用throws抛出创建该对象的异常类或其父类。
2、所调用的方法抛出了检查时异常时,如果该方法在调用的同时已经通过try-catch进行了处理,则可以不使用throws继续上抛该异常,否则必须使用throws才能上抛该异常,此时上抛的异常类可以是调用方法时方法抛出的异常类也可以是其父类。
我们可以用如下两个程序对这两点进行解释:
(1)未用try-catch语句处理该异常时:
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) throws Exception { //没有用try-catch语句接受该异常,则必须使用throws抛出创建该对象的异常类或其父类
if(age<0 || age>15) {
throw new AException("年龄要在0-15之间");
}else {
this.age = age;
}
}
}
此时调用者所调用的方法抛出了检查时异常,则必须使用try-catch处理该异常,或者也可以再用throws将该异常抛出:
public class Test {
public static void main(String[] args) /*throws Exception*/ { //也可以不用try-catch而是再用throws将该异常抛出
Student student = new Student();
try {
student.setAge(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(student.getAge());
}
}
(2)使用try-catch语句处理该异常时:
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) { //异常已经通过try-catch进行了处理,则可以不使用throws
if(age<0 || age>15) {
try {
throw new Exception("年龄要在0-15之间");
} catch (Exception e) {
e.printStackTrace();
}
}else {
this.age = age;
}
}
}
此时调用者也可以直接使用该方法
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setAge(100);
System.out.println(student.getAge());
}
}
总结:
如果throw抛出的是由运行时异常创建的对象,则不需要显式使用throws;否则需要显式使用throws或者直接try-catch-finally
throw与throws的区别:
抛出的东西不同 | 使用位置不同 | |
---|---|---|
throw | 抛出的是具体的异常对象 | 抛出的是抽象的异常类 |
throws | 一般用在方法体中,也可用在代码块中,但是如果抛出的是检查时异常类创建的对象,则必须使用try-catch自行处理 | throws只能用在方法声明括号后面 |
自定义异常类
1、但上例使用的异常类和提示信息不符合,不能见名知意。
2、故可以自定义一个异常类,该异常类需继承一个已有的异常类
3、如果自定义的异常继承检查时异常,则该自定义异常为检查时异常;如果继承运行时异常,则该自定义异常为运行时异常
4、如何定义:自定义异常类构造方法中调用父类一个含有String类型参数的构造方法,使得错误信息能在异常类对象printStackTrace方法和getMessage方法中使用。
例:
public class AgeException extends RuntimeException{//此时该自定义异常类为运行时异常
public AgeException(String msg) {//含一个String参数的构造方法
super(msg);
}
}
public class AgeException extends Exception{//此时该自定义异常类为检查时异常
public AgeException(String msg) {//含一个String参数的构造方法
super(msg);
}
}
则上述的代码均可通过该异常类表示:
运行时异常:
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0 || age>15) {
throw new AgeException("年龄要在0-15之间");//抛出一个自定义运行时异常给调用者
/*try {
throw new AgeException("年龄要在0-15之间");
} catch (AgeExceptione) {
e.printStackTrace();
}*/ //也可以通过try-catch来自行解决异常
}else {
this.age = age;
}
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setAge(100);//此时调用者可以直接使用该方法
/*try {
student.setAge(100);
} catch (AgeException e) {
e.printStackTrace();
}*/ //或者也可以用try-catch处理该异常
System.out.println(student.getAge());
}
}
检查时异常:
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) /*throws AgeException*/ { //亦可以用throws来将该异常抛给调用者
if(age<0 || age>15) {
try {
throw new AgeException("年龄要在0-15之间");
} catch (AgeExceptione) {
e.printStackTrace();
} //通过try-catch来自行解决检查时异常
}else {
this.age = age;
}
}
}
此时调用者可以使用try-catch处理该异常,或者也可以再用throws将该异常抛出:
public class Test {
public static void main(String[] args) /*throws AgeException*/ { //也可以不用try-catch而是再用throws将该异常抛出
Student student = new Student();
try {
student.setAge(100);
} catch (AgeException e) {
e.printStackTrace();
} //通过try-catch处理该异常
System.out.println(student.getAge());
}
}