Java中定义了大量的异常类,虽然这些异常类可以描述编程时出现的大部分异常情况,但是在程序开发中,有时还需要描述程序中特有的异常情况。为了解决这种情况,Java允许用户自定义异类。
一、首先自定义的异常类必需去继承Exception类或其子类。
二、在实际开发中如果没有特殊要求,自定义的异常类只需要继承Exception类。
例如:(随便写一个叫PrintfIsErrorException的自定义异常类,也就是能表明异常情况的名字)。
class PrintfIsErrorException extends Exception{
public PrintfIsErrorException(){
super(); //调用父类的默认无参数构造
}
public PrintfIsErrorException(String message){
super(message); //调用父类的有参构造
}
}
注意:
1、这里super(message):String message的message是为了描述出异常对象的信息的,实际上是调用父类中指定的构造方法,给异常信息的String变量赋值。当某个对象调用有异常抛出的方法时,也就是try代码块中的程序发生了异常,系统会将异常的信息封装成一个异常对象,并将这个对象传递给catch代码块进行处理, catch代码块需要一个参数指明它能够接受的异常类型。这个参数必须是Exception类或其子类(也就是我们自定义的异常类),例如:()(1)catch(PrintfIsErrorException e){ System.out.println(e.getMessage());}
(2)catch(PrintfIsErrorException e){e.printStackTrace();}。
其中这个printStackTrace()方法就是用于打印错误堆栈信息,简单说就是打印你的错误在哪一行代码并输出异常的消息字符串。简单的说e是捕获的能处理的异常对象,再通过对捕获的异常类型进行处理。其中调用的String getMessage()方法,这个方法打印的参数就是之前传进来的message,也就是该方法返回异常的消息字符串。
2、之所以父类有这个方法,其实Exception的父类Throwable所提供的方法,它继承过来的,Throwable类是所有异常类的父类,它还有一个直接子类叫Error类,Error类代表的是程序中所产生的错误, Exception类代表程序中产生的异常。
3、也可以这样写,但没必要因为自己的父类有现成的嘛(就好像家里有钱,还去外面借钱干嘛)
class PrintfIsErrorException extends Exception{
String message;
public PrintfIsErrorException(){
this.message="";
}
public PrintfIsErrorException(String message){
this.message=message;
}
public String getMessage(){
return message;
}
}
三、throws关键字,声明该方法有可能发生异常,当调用者在调用该方法时,就明确的知道该方法有异常,必须在程序中对异常进行处理,否则编译无法通过。(如果写的那个方法自己进行了try...catch捕获处理,就不需要用throws声明,简单来说因为自己已经处理好,不需要调用者来对异常进行处理,但是一般这样做,一般在方法体内用throw关键字抛出异常实例,然后再用throws向上声明该方法可能有异常,也就是抛给调用者)。
(1)注意用throws关键字在定义方法时的异常抛出的语法格式(下面举例如图)
[访问修饰符] [其他修饰符] 返回值类型 方法名 (参数列表) throws 异常类1,异常类2,...{
方法体
}
四、throw关键字抛出异常。但是注意用于方法内,抛出一个异常实例,注意且每次只能抛出一个异常实例。注意如果throw抛出的是Error、RuntimeException,或者它们的子类异常对象,则无需使用throws关键字或try...catch语句对异常进行处理。举例如下:(这里举例用到一个两数相除的方法)
public double divide()throws DivideIsZeroException { //向上抛出该方法可能会发生异常
double sum;
if(num2==0){
throw new DivideIsZeroException("除数不能为0!"); //这里就是抛出异常实例
}
sum=num1/num2;
return sum;
}
在该方法体中就用到throw关键字抛出异常实例,如果后面在主函数中调用会进行捕获处理该异常的对象,然后通过方法输出异常消息字符串。这里面new DivideIsZeroException("除数不能为0!")传进的参数就是message。
五、案例分析:
创建类Calc,定义2个数属性以及一个符号属性,编写4个方法add、minus、multiply、divide,4个方法分别进行2个小数的加、减、乘、除运算.在主函数里面接受用户输入2个运算数、1个运算符,根据该运算符选择应该调用哪一个方法进行运算。
代码如下:(代码注释有解释)
public class Calc {
double num1;
double num2;
String sign; //分别代表输入的两个小数和输入的运算符
public Calc(double num1,double num2,String sign){
this.num1=num1;
this.num2=num2; //类实例化对象时自动调用
this.sign=sign;
}
public double add(){ //两数相加
double sum;
sum=num1+num2;
return sum;
}
public double minus(){ //两数相减
double sum;
sum=num1-num2;
return sum;
}
public double multiply(){ //两数相乘
double sum;
sum=num1*num2;
return sum;
}
public double divide()throws DivideIsZeroException { //两数相除
//向上声明,抛出异常,交给调用者去处理
double sum;
if(num2==0){
throw new DivideIsZeroException("除数不能为0!"); //抛出异常实例
}
sum=num1/num2;
return sum;
}
public double Sign()throws DivideIsZeroException{ //该方法用来判断输入的运算符,然后再根据运算符调用不同的运算方法返回结果值
double count=0;
if(sign.contains("+")){
count=add();
}
if(sign.contains("-")){
count=minus();
}
if(sign.contains("*")){
count=multiply();
}
if(sign.contains("/")){
count=divide();
}
return count;
}
}
class DivideIsZeroException extends Exception{ //自定义异常类叫做”除数为0异常“,继承父类Exception
public DivideIsZeroException(){
//调用父类的默认无参数构造
super();
}
public DivideIsZeroException(String message){
super(message);//调用父类有参构造
}
}
测试代码如下:(主函数在其之中)
import java.util.*;
public class Test02 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请分别输入两位小数和运算符:(输入时中间用空格分隔!)");
while (sc.hasNext()) { //作用是一直可以测试不同的输入
String str[] = new String[3];
for (int i = 0; i < 3; i++) {
str[i] = sc.next();
}
double num1 = Double.parseDouble(str[0]);
double num2 = Double.parseDouble(str[1]); //用到包装类Double的parseDouble(String s)静态方法,直接用类名调用,该方法就是将字符串转换为对应的基本类型的数据
Calc c = new Calc(num1, num2, str[2]);
try {
System.out.printf(String.format("两个小数的运算结果为:%.4f(结果保留4位小数!)\n", c.Sign()));
} catch (DivideIsZeroException e) {
e.printStackTrace();
}
}
}
}
测试输入(2.2 2.2)代码的运行结果如下图:
也可以将catch代码块改成如下:
catch (DivideIsZeroException e) {
System.out.println(e.getMessage());
}
运行结果变成:(前面用的那个方法会打印错误堆栈信息,也就是会告诉你产生异常的位置,也就是你在哪个地方调用它,那时刚好出现了异常,在try中被捕获)