|
异常处理及自定义异常
一、处理异常
传统查看异常是看方法的返回值
返回0 表示正常运行结束
返回-1 表示某个参数不合法
返回-2 表示代码运行时某个外部条件未能满足
传统方法 将错误和正常的代码混在了一块,不好(其实我不太理解这里的混在一块或者 分开的意思)
面向对象处理机制 在代码执行过程中如果碰到不正常情况就会抛出一个异常对象,让实现正常功能代码块后面的可以捕获到这个异常并进行相应的处理,也可以不对异常进行处理,而是交给调用当前方法的调用者,或者调用者的调用者处理(这怎么就将正确代码和错误代码分开了??因为抛出的异常将错误代码定位了么?)
1.异常处理机制
异常两大类:
一:内存不足,硬件发生故障 (程序本身无法修复和处理的)
二:用户输入的数据类型或格式不合法等 (程序本身是可以修复和处理的)
进行异常处理的代码基本语法结构://该结构可以嵌套,但不常用
try //只有一个,包含可能发生异常的正常业务代码
{//正常代码
}
catch(异常类型 名称) //可以有一个或者多个,负责处理异常
{
//异常处理代码
}
finally //可以没有或者只有一个,无论是否产生异常都要执行
{
//必须执行的代码块
}
2.异常处理示例
传统情况下,如果遇到被除数为0的情况会被异常终止
如果采用异常机制进行处理,程序可以在相关处理完成后继续运行,或者由于运行条件不足不能继续运行,但至少可以让程序体面的结束
(1)在主程序中处理异常
package unit_7;
class Math
{
public static int div(int a, int b)
{
int c;
c = a/b;
return c;
}
}
public class TestMath {
public static void main(String[] args)
{
int a = 10;
int b = 0;
try{//如果被try包含的代码有好几行,那么中间任一行发生了错误该行后面的代码将不会在被执行
System.out.println(Math.div(a,b));
}
catch (ArithmeticException ae)
{
System.out.println("调用方法div时产生了一个算术异常!");
}
catch (Exception ae)
{
System.out.println("调用方法div时产生了一个未知异常!");
}
finally//finally好像必须直接跟在try或者catch后面如果前面有其他的语句好像就会报错,如果这里把finally删掉下面这个语句仍然会运行,但是在发生异常的情况下如果catch中在代码块的结尾处加上return或者正常结束情况下如果try中在代码块结尾处加上return;,有finally可以输出"finally代码块在正常运行",没有则不能输出,但是如果在程序中加入System.exit,finally语句将不会被执行,因为return是结束方法而system是结束程序,return是退出主方法么,如果是退出主方法那么不是应该还是可以执行后面的句子,不然是退出到哪里去了,还有书上说当执行到return指令的时候,方法将结束运行,但如果return后面还有表达式,可以先计算表达式的值,并将计算得到的结果作为方法的返回值是什么意思,为什么有表达式还可以继续执行而输出语句却不可以?。
{
System.out.println("finally代码块在正常运行");
}
}
}
(2)在调用方法中处理异常
就是把处理异常的代码挪到方法里面去,无论是否发生异常(在主方法里面处理异常也是一样的)(前提是处理异常代码中没有return),在处理异常代码块的后面的代码仍然执行
(3)由Java虚拟机处理异常
将(1)中的捕获这处理异常的代码删去再执行,那么程序就会终止并且报错。
(4)Finally代码块的执行(见在主程序中调用异常)
二、抛出异常
异常分为二类:(大概是为了后面好描述的另一种分类标准,但是分类标准太多会让人忧伤的)
可预测异常
运行时异常
(1)通过throws抛出要求调用处理者的异常
throws 抛出的所有可检查异常都必须被捕获与处理。(应该是)
感觉是在调用后面跟了throws+该方法可能发生的异常的方法(例如: public boolean createNewFile() throws IOException)时必须用try将这个方法括起来,并且在后面配置catch语句来捕捉该方法可能发生的异常。如果不加处理异常语句就无法正常编译。应该算是一个提醒作用吧。提醒这个语句可能会有异常,然后提前写好try-catch语句来以防万一。
(2)通过throw抛出异常
throw可以在try 或者catch语句中或者不在try和catch语句中抛出异常(如果在一个方法中使用throw抛出异常最好在方法名后面使用throws列出这些异常,这样方便调用者知道这个方法可能会抛出什么样的异常)
class Math
{
public static int div(int a, int b)
{
int c = 0;
try{
c = a/b; return c;
}
catch (ArithmeticException ae)
{
System.out.println("调用方法div时产生了一个算术异常!");
throw ae;//1.不理解这里抛出去的为什么外面会接到,2因为在这里处理了异常主函数那里就不会抛出异常了?
}
catch (Exception ae)
{
System.out.println("调用方法div时产生了一个未知异常!");
//throw ae;//如果在这里增加这条语句会报错为什么
}
return c;
}
}
public class TestMath {
public static void main(String[] args)
{
int a = 10;
int b = 0;
try{
System.out.println(Math.div(a,b));
}
catch (ArithmeticException ae)
{
System.out.println("调用方法div时产生了一个算术异常!");
}
catch (Exception ae)
{
System.out.println("调用方法div时产生了一个未知异常!");
}
}
}
三、自定义异常
(1)异常的继承关系
异常类直接或者间接的继承于Exception类,Exception(提供4个和Throwable(的构造器?)形式相同的构造器)和error(error一般表示程序中出现的严重问题,在程序中不会被捕获)类继承 Throwable继承 Object。
一个对象只有是Throwable或者其子类的实例才可以被Java虚拟机或者throw语句抛出。
Throwable除了继承Object以外,还实现了接口Serializable,这意味着Throwable可以被序列化(序列化:可以被保存于文件之中或者在网络中被传送)
Throwable还包含抛出对象的详细信息和产生该对象的原因。
Throwable类有4个重载构造器:
1.Throwable(),不包含任何参数,可以构建一个详细消息为null的Throwable类
2.Throwable(String message),message可以用于指定新构建Throwable对象的详细信息
3.Throwable(String message,Throwable cause)可以在构造对象时指定Throwable对象的消息和原因
4.Throwable(Throwable cause)只有一个参数,但它可以
Throwable比较重要的方法为getMessage和printStackTrace
getMessage:返回当前对象的详细消息字符串,即在构造器中传入的字符串
printStackTrace:将当前Throwable对象的堆栈跟踪至错误输出流,它在调试程序时对于帮助开发者查找异常产生的位置能够提供十分有用的信息(该信息在正式产品中一般输入到LOG中)
class Math
{
public static int div(int a, int b)
{
int c = 0;
c = a/b;
return c;
}
}
public class TestMath {
public static void main(String[] args)
{
int a = 10;
int b = 0;
try{
System.out.println(Math.div(a,b));
}
catch (ArithmeticException ae)
{
System.out.println("调用方法div时产生了一个算术异常!");
System.out.println("ae.getMessage()这个文字到哪里去了"+ae.getMessage());
ae.printStackTrace();
}
}
}
输出:
调用方法div时产生了一个算术异常!
java.lang.ArithmeticException: / by zero//这个输出是上面代码主方法里面catch语句的是第三行输出的结果
ae.getMessage()这个文字到哪里去了/ by zero//这个输出是上面代码主方法里面catch语句的第二行的输出结果
at unit_7.Math.div(TestMath.java:9)//后面两行是第三行的输出结果
at unit_7.TestMath.main(TestMath.java:22)
(2)实现自定义的继承类
自定义异常类继承Exception类,根据需要调用Exception的方法和构造器
package unite_8;
public class DivZeroException extends Exception
{
private int divedNumber;
public DivZeroException(int divedNumber)
{
super("除零异常!");
this.divedNumber = divedNumber;
}
public DivZeroException(String message, int divedNumber)
{
super(message);
this.divedNumber = divedNumber;
}
public int getDivedNumber()
{
return divedNumber;
}
}
class Math
{
public static double div(int a,int b)
throws DivZeroException
{
if (b==0)
throw new DivZeroException(b);
double ret = 0;
ret = a/b;
return ret;
}
}
package unite_8;
public class TestDivZeroException
{
public static void main(String[] args)
{
int x =10;
int y=0;
try{
System.out.println(Math.div(x, y));
}
catch(DivZeroException dze)
{
System.out.println(dze.getMessage());
System.out.println(dze.getDivedNumber());
}
catch(Exception e)
{
System.out.println("产生了一个未知异常");
}
}
}
如果希望DivZeroException在更多的数据类型下得以应用,易想到将DivZeroException声明为泛型类,但是只有在JDK1.5以及以上的版本才可以将异常类声明为泛型类。
如果使用泛型则定义如下
public class DivZeroException<T> extends Exception
{
private T divedNumber;
public DivZeroException(T divedNumber)
{
super("除零异常!");
this.divedNumber = divedNumber;
}
public DivZeroException(String message, T divedNumber)
{
super(message);
this.divedNumber = divedNumber;
}
public T getDivedNumber()
{
return divedNumber;
}
}
(3)重写方法时的异常处理
重写方法不可以抛出被重写方法所声明之外的异常。
package unite_8;
class Aexception extends Exception
{}
class Bexception extends Exception
{}
class FatherClass
{
public void fun()throws Aexception{}
}
class SonClass extends FatherClass
{
public void fun()throws Bexception{}{}//这里抛出Bexception报错,只能抛出Aexception或者不抛出
}
重写方法可以抛出被重写方法抛出异常的子类。
(这里和重写父类方法的重写方法的返回值可以是被重写方法的返回值或者是该返回值的子类有点类似)
如果将上面的这句代码class Bexception extends Exception{}句末尾的exception改为Aexception就不会报错了。
四、断言
是一种调试机制
用JRE,它将被忽略
使用JDK时需要使用“-ea”参数才可以生效(使用cmd 我这里使用eclipse直接将这个断言忽略了)
package unit_7;
class Tassert
{
private void fun(int x)
{
assert x!=0:"参数为0!";//定义格式,如果后面的表达式为假则抛出后面的那句话
System.out.println(100/x);
}
public void callFun()
{
fun(0);
}
}
public class TestAssert {
public static void main(String[] args)
{
Tassert ta = new Tassert();
ta.callFun();
}
}
五、习题
(1)假如某高校规定每个学生每学期除必修课外,至少要选择两门选修课。请定义一个异常类,当学生的选课不符合要求时抛出该异常;
(2)编程实现为考生录入成绩时,如果输入的成绩不再合理范围内,则抛出成绩异常错误,并在适当的位置对该异常进行处理
package unite_8;
class OverRange extends Exception
{
private int num;
public OverRange(int num)
{
super("不在有意义的范围内");
}
}
class Student
{
private int grade;
public void inputGrade(int grade)throws OverRange
{
if(grade>100||grade<0)
{
throw new OverRange(grade);
}
}
}
public class Question_2 {
public static void main(String[] args)
{
Student s = new Student();
try{
s.inputGrade(189);
}
catch(OverRange or)
{
System.out.println(or.getMessage());
}
catch(Exception e)
{
System.out.println("捕获未知异常");
}
}
}
小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)
GMT+8, 2024-5-17 09:46
Powered by Discuz! X3.4
© 2001-2023 Discuz! Team.