2020/1/281第6章异常处理、递归和单体程序设计方法2020/1/282本章总体纲要•异常处理•递归方法•单体(Singleton)程序设计模式2020/1/283生活中的异常•正常情况下,小王每日开车去上班,耗时大约30分钟•但是,异常情况迟早要发生!一路畅通堵车!撞车!2020/1/284程序中的异常publicclassHello{publicstaticvoidmain(String[]args){System.out.print(请输入课程代号(1至3之间的数字):);Scannerin=newScanner(System.in);intcourseCode=in.nextInt();//从键盘输入整数switch(courseCode){case1:System.out.println(C#编程);break;case2:System.out.println(Java编程);break;case3:System.out.println(SQL基础);}}}输入:2输出:Java编程输入:B程序中断运行!正常情况:异常情况:2020/1/285什么是异常•异常就是在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序绕行或者等待请求交警解决异常!•面对异常该怎么办呢?通常情况下,我们会这样处理:程序运行程序中断运行堵车!撞车!生活中,我们会根据不同的异常进行相应的处理,而不会就此中断我们的生活2020/1/286什么是异常处理•Java编程语言使用异常处理机制为程序提供了错误处理的能力程序中预先想好了对付异常的处理办法异常!程序运行处理完毕,程序继续运行对异常进行处理2020/1/287为什么需要异常?•强制程序异常/错误处理–同时指定需要异常的种类•异常处理模型提供了一种统一处理异常/错误的模式–传统程序方法:设置标志位,或返回错误码,分别处理各种异常情况。但在编程时常常出现这样的情况:忘了对某些异常情况进行处理,尤其是当存在多个分支或者多个开发人员共同开发程序时。–简化对异常情况的处理,减少if-else语句2020/1/288Java中如何进行异常处理•Java的异常处理是通过5个关键字来实现的:try、catch、finally、throw、throws捕获异常catchtryfinally执行可能产生异常的代码捕获异常无论是否发生异常,代码总能执行手动抛出异常抛出异常throw声明异常声明方法可能要抛出的各种异常throws2020/1/289格式•在try语句块中包含可能会产生异常的语句•紧接着若干个catch语句块,进行异常处理•catch语句块与finally语句块至少存在一个try{//可能会抛出异常的代码}catch(ExceptionTyperef){//异常处理代码}finally{//…}2020/1/2810什么时候会发生异常?•数组的下标越界•打开不存在的文件•网络无法连接•操作数超出所要求的范围•少了所需加载的类,•自定义异常,要求程序处理2020/1/2811处理异常的几种常用方法1.一旦捕获异常,马上进行处理2.重新抛出异常3.捕获异常,但并不处理4.通过语句System.exit()退出应用程序2020/1/2812异常(Exceptions)类型•常见异常–内存耗尽–数组下标越界–除数为0–非法的参数(方法的参数)2020/1/2813异常(Exception)的层次结构2020/1/2814运行时发生的异常(RuntimeExceptions)•异常随时都可以发生–ArrayIndexOutOfBoundsException–NullPointerException–定义了引用,但不指向任何对象(object)–ClassCastException•数据类型间的转换不合法•良好的编程习惯,可以减少很多异常的发生2020/1/2815受检异常和非受检异常•受检异常–必须在方法声明时通过throws列出–在编译时就能被检测出•非受检测异常–不必在throws列表中–错误(Errors)和运行时异常(RuntimeExceptions)•受检异常,必须处理才能通过编译•运行时异常只有在运行时才能被发现•错误常常指的是致命性错误,常常也无法处理2020/1/2816处理多种异常(Exception)类型•如果含有多处catch语句块,则异常会被第一个与其相匹配的catch语句块处理2020/1/2817finally语句块•在异常处理过程中,finally语句块总是会被执行到:无论有没有异常发生,也无论有没有异常被捕捉到–可选项:finally语句块,通常位于catch语句块的后面–可以用来释放try语句块中获得的资源•例如,关闭在try语句块中打开的文件2020/1/2818throws列表•在方法的声明处列出所有的受检异常返回类型方法名(参数列表)throws异常类型1,异常类型2,…{//方法体}–在本方法内就可以不处理这些异常–调用该方法的方法就必须处理这些异常•示例:publicstaticvoidg()throwsException{thrownewException();}//方法g结束2020/1/2819异常处理:捕捉-或者-声明•如果一个方法调用一个抛出受检异常的方法(含有throws列表的方法),则该方法必须捕捉这些受检异常,或通过throws列表声明这些异常2020/1/2820重新抛出异常•如果catch语句块不处理某种异常,可以重新抛出异常–抛出异常的方法:throwe;–由其外层的try-catch语句块处理2020/1/2821publicclassJ_Exception{publicstaticvoidmb_throwException(){System.out.println(产生并抛出ArithmeticException类型的异常);thrownewArithmeticException();}publicstaticvoidmb_catchArrayException(){try{mb_throwException();System.out.println(在try语句块中的多余语句);}catch(ArrayIndexOutOfBoundsExceptione){System.err.println(方法mb_catchArrayException捕捉到异常);}finally{System.out.println(方法mb_catchArrayException的finally语句块);}//try-catch-finally结构结束System.out.println(方法mb_catchArrayException运行结束);}publicstaticvoidmain(Stringargs[]){try{mb_catchArrayException();}catch(ArithmeticExceptione){System.err.println(方法main捕捉到异常);}finally{System.out.println(方法main的finally语句块);}//try-catch-finally结构结束System.out.println(异常处理结束);}//方法main结束}抛出异常,在该函数中不处理不执行执行捕获异常2020/1/2822classJ_ExceptionNewextendsException{privatestaticintm_number=0;publicJ_ExceptionNew(){m_number++;}//J_ExceptionNew构造方法结束publicStringtoString(){return(新异常出现+m_number+次);}//方法toString结束}//类J_ExceptionNew结束自定义异常例程publicclassJ_ExceptionNewExample{publicstaticvoidmain(Stringargs[]){try{thrownewJ_ExceptionNew();}catch(J_ExceptionNewe){System.err.println(e);}//try-catch结构结束}//方法main结束}//类J_ExceptionNewExample结束调用toString方法创建异常对象,抛出异常2020/1/2823示例Importjava.util.*;publicclassExceptionDemo{publicstaticvoidmain(String[]args){Scannerin=newScanner(System.in);try{System.out.print(“请输入S1的总学时:);inttotalTime=in.nextInt();//总学时System.out.print(“请输入S1的课程数目:);inttotalCourse=in.nextInt();//课程数目System.out.println(“S1各课程的平均学时为:+totalTime/totalCourse);}catch(InputMismatchExceptione1){System.out.println(输入不为数字!);}catch(ArithmeticExceptione2){System.out.println(课程数目不能为零!);}catch(Exceptione){System.out.println(发生错误:+e.getMessage());}}}输入:270H在安排catch语句的顺序时,首先应该捕获最特殊的异常,然后再逐渐一般化,即先子类后父类输出:输入不为数字!进入第一个catch块输入:2700输出:课程数目不能为零!进入第二个catch块2020/1/2824本章总体纲要•异常处理•递归方法•单体(Singleton)程序设计模式2020/1/2825递归•如果在方法定义中直接或间接地调用该方法本身,就称为递归2020/1/2826汉诺塔(TowerofHanoi)问题•有三根柱子:S、T和E•柱子S上套着n个盘,小盘依次在大盘上面•现在要求:1.每次只能将一根柱子最上面的一个盘移动到另一根柱子上2.不允许将大盘放在小盘上面3.只能利用这三根柱子4.将在柱子S上的n个盘移动到柱子E上2020/1/2827利用递归求解汉诺塔问题的例程publicclassJ_Hanoi{publicstaticvoidmb_hanoi(intn,charstart,chartemp,charend){if(n=1)System.out.println(将盘从+start+移到+end);else{mb_hanoi(n-1,start,end,temp);System.out.println(将盘从+start+移到+end);mb_hanoi(n-1,temp,start,end);}//if-else结构结束}//方法mb_hanoi结束publicstaticvoidmain(Stringargs[]){mb_hanoi(3,'S','T','E');}//方法main结束}//类J_Hanoi结束J_Hanoi.java;2020/1/2828编译、运行&结果2020/1/2829本章总体纲要•异常处理•递归方法•单体(Singleton)程序设计模式2020/1/2830单体程序设计模式•要让一个类只能有一个实例对象2020/1/2831单体类实现例程publicclassJ_Singleton{privatestaticJ_Singletonm_object=newJ_Singleton();privateJ_Singleton(){}//J_Singleton构造方法结束//返回单体实例对象的引用publicstaticJ_Singletonmb_getObject(){retur