㈠ java中exception的处理
有catch 就说明处理了 就算catch里面什么也不写 那也叫空处理 错误不会影响程序继续运行
你说那个 叫 throw 是往外抛异常 如果外层没有处理 即外层没有 try catch 继续向外跑
直到被处理 如果一直没处理 就会报错
㈡ java异常处理详解!!
异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C开始,你也许已经知道如何用if...else...来控制异常了,也许是自发的,然而这种控制异常痛苦,同一个异常或者错误如果多个地方出现,那么你每个地方都要做相同处理,感觉相当的麻烦! Java语言在设计的当初就考虑到这些问题,提出异常处理的框架的方案,所有的异常都可以用一个类型来表示,不同类型的异常对应不同的子类异常(这里的异常包括错误概念),定义异常处理的规范,在1.4版本以后增加了异常链机制,从而便于跟踪异常!这是Java语言设计者的高明之处,也是Java语言中的一个难点,下面是我对Java异常知识的一个总结,也算是资源回收一下。
一、Java异常的基础知识
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出java.lang.ArithmeticException的异常。 有些异常需要做处理,有些则不需要捕获处理,后面会详细讲到。 天有不测风云,人有旦夕祸福,Java的程序代码也如此。在编程过程中,首先应当尽可能去避免错误和异常发生,对于不可避免、不可预测的情况则在考虑异常发生时如何处理。 Java中的异常用对象来表示。Java对异常的处理是按异常分类处理的,不同异常有不同的分类,每种异常都对应一个类型(class),每个异常都对应一个异常(类的)对象。 异常类从哪里来?有两个来源,一是Java语言本身定义的一些基本异常类型,二是用户通过继承Exception类或者其子类自己定义的异常。Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。 异常的对象从哪里来呢?有两个来源,一是Java运行时环境自动抛出系统生成的异常,而不管你是否愿意捕获和处理,它总要被抛出!比如除数为0的异常。二是程序员自己抛出的异常,这个异常可以是程序员自己定义的,也可以是Java语言中定义的,用throw 关键字抛出异常,这种异常常用来向调用者汇报异常的一些信息。 异常是针对方法来说的,抛出、声明抛出、捕获和处理异常都是在方法中进行的。 Java异常处理通过5个关键字try、catch、throw、throws、finally进行管理。基本过程是用try语句块包住要监视的语句,如果在try语句块内出现异常,则异常会被抛出,你的代码在catch语句块中可以捕获到这个异常并做处理;还有以部分系统生成的异常在Java运行时自动抛出。你也可以通过throws关键字在方法上声明该方法要抛出异常,然后在方法内部通过throw抛出异常对象。finally语句块会在方法执行return之前执行,一般结构如下: try{ 程序代码 }catch(异常类型1 异常的变量名1){ 程序代码 }catch(异常类型2 异常的变量名2){ 程序代码 }finally{ 程序代码 } catch语句可以有多个,用来匹配多个异常,匹配上多个中一个后,执行catch语句块时候仅仅执行匹配上的异常。catch的类型是Java语言中定义的或者程序员自己定义的,表示代码抛出异常的类型,异常的变量名表示抛出异常的对象的引用,如果catch捕获并匹配上了该异常,那么就可以直接用这个异常变量名,此时该异常变量名指向所匹配的异常,并且在catch代码块中可以直接引用。这一点非常非常的特殊和重要! Java异常处理的目的是提高程序的健壮性,你可以在catch和finally代码块中给程序一个修正机会,使得程序不因异常而终止或者流程发生以外的改变。同时,通过获取Java异常信息,也为程序的开发维护提供了方便,一般通过异常信息就很快就能找到出现异常的问题(代码)所在。 Java异常处理是Java语言的一大特色,也是个难点,掌握异常处理可以让写的代码更健壮和易于维护。
二、Java异常类类图
下面是这几个类的层次图: java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.Error java.lang.ThreadDeath
下面四个类的介绍来自java api 文档。
1、Throwable Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。 两个子类的实例,Error 和 Exception,通常用于指示发生了异常情况。通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。
2、Exception Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件,表示程序本身可以处理的异常。
3、Error Error 是 Throwable 的子类,表示仅靠程序本身无法恢复的严重错误,用于指示合理的应用程序不应该试图捕获的严重问题。 在执行该方法期间,无需在方法中通过throws声明可能抛出但没有捕获的 Error 的任何子类,因为Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try...catch语句捕获它,也没有用throws字句声明抛出它,还是会编译通过。
4、RuntimeException RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try...catch语句捕获它,也没有用throws字句声明抛出它,还是会编译通过,这种异常可以通过改进代码实现来避免。
5、ThreadDeath 调用 Thread 类中带有零参数的 stop 方法时,受害线程将抛出一个 ThreadDeath 实例。 仅当应用程序在被异步终止后必须清除时才应该捕获这个类的实例。如果 ThreadDeath 被一个方法捕获,那么将它重新抛出非常重要,因为这样才能让该线程真正终止。 如果没有捕获 ThreadDeath,则顶级错误处理程序不会输出消息。 虽然 ThreadDeath 类是“正常出现”的,但它只能是 Error 的子类而不是 Exception 的子类,因为许多应用程序捕获所有出现的 Exception,然后又将其放弃。
以上是对有关异常API的一个简单介绍,用法都很简单,关键在于理解异常处理的原理,具体用法参看Java API文档。
三、Java异常处理机制
对于可能出现异常的代码,有两种处理办法: 第一、在方法中用try...catch语句捕获并处理异常,catach语句可以有多个,用来匹配多个异常。例如: public void p(int x){ try{ ... }catch(Exception e){ ... }finally{ ... } }
第二、对于处理不了的异常或者要转型的异常,在方法的声明处通过throws语句抛出异常。例如: public void test1() throws MyException{ ... if(....){ throw new MyException(); } } 如果每个方法都是简单的抛出异常,那么在方法调用方法的多层嵌套调用中,Java虚拟机会从出现异常的方法代码块中往回找,直到找到处理该异常的代码块为止。然后将异常交给相应的catch语句处理。如果Java虚拟机追溯到方法调用栈最底部main()方法时,如果仍然没有找到处理异常的代码块,将按照下面的步骤处理: 第一、调用异常的对象的printStackTrace()方法,打印方法调用栈的异常信息。 第二、如果出现异常的线程为主线程,则整个程序运行终止;如果非主线程,则终止该线程,其他线程继续运行。 通过分析思考可以看出,越早处理异常消耗的资源和时间越小,产生影响的范围也越小。因此,不要把自己能处理的异常也抛给调用者。 还有一点,不可忽视:finally语句在任何情况下都必须执行的代码,这样可以保证一些在任何情况下都必须执行代码的可靠性。比如,在数据库查询异常的时候,应该释放JDBC连接等等。finally语句先于return语句执行,而不论其先后位置,也不管是否try块出现异常。finally语句唯一不被执行的情况是方法执行了System.exit()方法。System.exit()的作用是终止当前正在运行的 Java 虚拟机。finally语句块中不能通过给变量赋新值来改变return的返回值,也建议不要在finally块中使用return语句,没有意义还容易导致错误。
最后还应该注意一下异常处理的语法规则: 第一、try语句不能单独存在,可以和catch、finally组成 try...catch...finally、try...catch、try...finally三种结构,catch语句可以有一个或多个,finally语句最多一个,try、catch、finally这三个关键字均不能单独使用。 第二、try、catch、finally三个代码块中变量的作用域分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。 第三、多个catch块时候,Java虚拟机会匹配其中一个异常类或其子类,就执行这个catch块,而不会再执行别的catch块。 第四、throw语句后不允许有紧跟其他语句,因为这些没有机会执行。 第五、如果一个方法调用了另外一个声明抛出异常的方法,那么这个方法要么处理异常,要么声明抛出。
那怎么判断一个方法可能会出现异常呢?一般来说,方法声明的时候用了throws语句,方法中有throw语句,方法调用的方法声明有throws关键字。
throw和throws关键字的区别 throw用来抛出一个异常,在方法体内。语法格式为:throw 异常对象。 throws用来声明方法可能会抛出什么异常,在方法名后,语法格式为:throws 异常类型1,异常类型2...异常类型n。
四、如何定义和使用异常类
1、使用已有的异常类,假如为IOException、SQLException。 try{ 程序代码 }catch(IOException ioe){ 程序代码 }catch(SQLException sqle){ 程序代码 }finally{ 程序代码 }
2、自定义异常类 创建Exception或者RuntimeException的子类即可得到一个自定义的异常类。例如: public class MyException extends Exception{ public MyException(){} public MyException(String smg){ super(smg); } }
3、使用自定义的异常 用throws声明方法可能抛出自定义的异常,并用throw语句在适当的地方抛出自定义的异常。例如: 在某种条件抛出异常 public void test1() throws MyException{ ... if(....){ throw new MyException(); } }
将异常转型(也叫转译),使得异常更易读易于理解 public void test2() throws MyException{ ... try{ ... }catch(SQLException e){ ... throw new MyException(); } }
还有一个代码,很有意思: public void test2() throws MyException{ ... try { ... } catch (MyException e) { throw e; } }
这段代码实际上捕获了异常,然后又和盘托出,没有一点意义,如果这样还有什么好处理的,不处理就行了,直接在方法前用throws声明抛出不就得了。异常的捕获就要做一些有意义的处理。
五、运行时异常和受检查异常
Exception类可以分为两种:运行时异常和受检查异常。 1、运行时异常 RuntimeException类及其子类都被称为运行时异常,这种异常的特点是Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try...catch语句捕获它,也没有用throws字句声明抛出它,还是会编译通过。例如,当除数为零时,就会抛出java.lang.ArithmeticException异常。 2、受检查异常 除了RuntimeException类及其子类外,其他的Exception类及其子类都属于受检查异常,这种异常的特点是要么用try...catch捕获处理,要么用throws语句声明抛出,否则编译不会通过。 3、两者的区别 运行时异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误的操作。一旦出现错误,建议让程序终止。 受检查异常表示程序可以处理的异常。如果抛出异常的方法本身不处理或者不能处理它,那么方法的调用者就必须去处理该异常,否则调用会出错,连编译也无法通过。当然,这两种异常都是可以通过程序来捕获并处理的,比如除数为零的运行时异常: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!!!"); try{ System.out.println(1/0); }catch(ArithmeticException e){ System.out.println("除数为0!"); } System.out.println("除数为零后程序没有终止啊,呵呵!!!"); } }
运行结果:
Hello World!!! 除数为0! 除数为零后程序没有终止啊,呵呵!!!
4、运行时错误 Error类及其子类表示运行时错误,通常是由Java虚拟机抛出的,JDK中与定义了一些错误类,比如VirtualMachineError 和OutOfMemoryError,程序本身无法修复这些错误.一般不去扩展Error类来创建用户自定义的错误类。而RuntimeException类表示程序代码中的错误,是可扩展的,用户可以创建特定运行时异常类。 Error(运行时错误)和运行时异常的相同之处是:Java编译器都不去检查它们,当程序运行时出现它们,都会终止运行。
5、最佳解决方案 对于运行时异常,我们不要用try...catch来捕获处理,而是在程序开发调试阶段,尽量去避免这种异常,一旦发现该异常,正确的做法就会改进程序设计的代码和实现方式,修改程序中的错误,从而避免这种异常。捕获并处理运行时异常是好的解决办法,因为可以通过改进代码实现来避免该种异常的发生。 对于受检查异常,没说的,老老实实去按照异常处理的方法去处理,要么用try...catch捕获并解决,要么用throws抛出! 对于Error(运行时错误),不需要在程序中做任何处理,出现问题后,应该在程序在外的地方找问题,然后解决。
六、异常转型和异常链 异常转型在上面已经提到过了,实际上就是捕获到异常后,将异常以新的类型的异常再抛出,这样做一般为了异常的信息更直观!比如: public void run() throws MyException{ ... try{ ... }catch(IOException e){ ... throw new MyException(); }finally{ ... } }
异常链,在JDK1.4以后版本中,Throwable类支持异常链机制。Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。最后,它还可以包含 cause(原因):另一个导致此 throwable 抛出的 throwable。它也称为异常链 设施,因为 cause 自身也会有 cause,依此类推,就形成了异常链,每个异常都是由另一个异常引起的。 通俗的说,异常链就是把原始的异常包装为新的异常类,并在新的异常类中封装了原始异常类,这样做的目的在于找到异常的根本原因。
通过Throwable的两个构造方法可以创建自定义的包含异常原因的异常类型: Throwable(String message, Throwable cause) 构造一个带指定详细消息和 cause 的新 throwable。 Throwable(Throwable cause) 构造一个带指定 cause 和 (cause==null ? null :cause.toString())(它通常包含类和 cause 的详细消息)的详细消息的新 throwable。 getCause() 返回此 throwable 的 cause;如果 cause 不存在或未知,则返回 null。 initCause(Throwable cause) 将此 throwable 的 cause 初始化为指定值。 在Throwable的子类Exception中,也有类似的指定异常原因的构造方法: Exception(String message, Throwable cause) 构造带指定详细消息和原因的新异常。 Exception(Throwable cause) 根据指定的原因和 (cause==null ? null : cause.toString()) 的详细消息构造新异常(它通常包含 cause 的类和详细消息)。 因此,可以通过扩展Exception类来构造带有异常原因的新的异常类。
七、Java异常处理的原则和技巧
1、避免过大的try块,不要把不会出现异常的代码放到try块里面,尽量保持一个try块对应一个或多个异常。 2、细化异常的类型,不要不管什么类型的异常都写成Excetpion。 3、catch块尽量保持一个块捕获一类异常,不要忽略捕获的异常,捕获到后要么处理,要么转译,要么重新抛出新类型的异常。 4、不要把自己能处理的异常抛给别人。 5、不要用try...catch参与控制程序流程,异常控制的根本目的是处理程序的非正常情况。
㈢ 常见JAVA运行时异常有哪些
1,java.lang.NullPointerException
这个异常的解释是 "程序遇上了空指针 ",简单地说就是调用了未经初始化的对象或者是不存在的对象,这个错误经常出现在创建图片,调用数组这些操作中,比如图片未经初始化,或者图片创建时的路径错误等等。
2,java.lang.ClassNotFoundException
异常的解释是"指定的类不存在",这里主要考虑一下类的名称和路径是否正确即可
3,java.lang.
这个异常的解释是"数组下标越界",现在程序中大多都有对数组的操作,因此在调用数组的时候一定要认真检查,看自己调用的下标是不是超出了数组的范围,一般来说,显示(即直接用常数当下标)调用不太容易出这样的错,但隐式(即用变量表示下标)调用就经常出错了.
4,java.lang.NoSuchMethodError
方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。
5,java.lang.IndexOutOfBoundsException
索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。
6,java.lang.NumberFormatException
数字格式异常。当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。
7,java.sql.SQLException
Sql语句执行异常
8,java.io.IOException
输入输出异常
9,java.lang.IllegalArgumentException
方法参数错误
10java.lang.IllegalAccessException
无访问权限异常
(3)java异常框架扩展阅读:
Java技术应用领域:
1、Android应用
许多的 Android应用都是Java程序员开发者开发。虽然 Android运用了不同的JVM以及不同的封装方式,但是代码还是用Java语言所编写。相当一部分的手机中都支持JAVA游戏,这就使很多非编程人员都认识了JAVA。
2、在金融业应用的服务器程序
Java在金融服务业的应用非常广泛,很多第三方交易系统、银行、金融机构都选择用Java开发,因为相对而言,Java较安全 。大型跨国投资银行用Java来编写前台和后台的电子交易系统,结算和确认系统,数据处理项目以及其他项目。
3、网站
Java 在电子商务领域以及网站开发领域占据了一定的席位。开发人员可以运用许多不同的框架来创建web项目,SpringMVC,Struts2.0以及frameworks。即使是简单的 servlet,jsp和以struts为基础的网站在政府项目中也经常被用到。例如医疗救护、保险、教育、国防以及其他的不同部门网站都是以Java为基础来开发的。
4、嵌入式领域
Java在嵌入式领域发展空间很大。在这个平台上,只需130KB就能够使用Java技术(在智能卡或者传感器上)。
5、大数据技术
Hadoop以及其他大数据处理技术很多都是用Java,例如Apache的基于Java的HBase和Accumulo以及 ElasticSearchas。
6、高频交易的空间
Java平台提高了这个平台的特性和即使编译,他同时也能够像 C++ 一样传递数据。正是由于这个原因,Java成为的程序员编写交易平台的语言,因为虽然性能不比C++,但开发人员可以避开安全性,可移植性和可维护性等问题。
7、科学应用
Java在科学应用中是很好选择,包括自然语言处理。最主要的原因是因为Java比C++或者其他语言相对其安全性、便携性、可维护性以及其他高级语言的并发性更好。
㈣ Java异常机制是什么
一、异常的关键字:
一般来说,异常的关键字有:try、catch、finally、throw、throws。
网上的资料对这几个关键字是这样解释的:
try: Opening exception-handling statement.
catch: Captures the exception.
finally: Runs its code before terminating the program.
throws: Lists the exceptions a method could throw.
Throw: Transfers control of the method to the exception handler.
try语句
try语句用大括号{}指定了一段代码,该段代码可能会抛弃一个或多个例外。
catch语句
catch语句的参数类似于方法的声明,包括一个例外类型和一个例外对象。例外类型必须为Throwable类的子类,它指明了catch语句所处理的例外类型,例外对象则由运行时系统在try所指定的代码块中生成并被捕获,大括号中包含对象的处理,其中可以调用对象的方法。
catch语句可以有多个,分别处理不同类的例外。Java运行时系统从上到下分别对每个catch语句处理的例外类型进行检测,直到找到类型相匹配的catch语句为止。这里,类型匹配指catch所处理的例外类型与生成的例外对象的类型完全一致或者是它的父类,因此,catch语句的排列顺序应该是从特殊到一般。也可以用一个catch语句处理多个例外类型,这时它的例外类型参数应该是这多个例外类型的父类,程序设计中要根据具体的情况来选择catch语句的例外处理类型。
finally语句
try所限定的代码中,当抛弃一个例外时,其后的代码不会被执行。通过finally语句可以指定一块代码。无论try所指定的程序块中抛弃或不抛弃例外,也无论catch语句的例外类型是否与所抛弃的例外的类型一致,finally所指定的代码都要被执行,它提供了统一的出口。通常在finally语句中可以进行资源的清除工作。如关闭打开的文件等。
throws语句
throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常。对大多数Exception子类来说,Java 编译器会强迫你声明在一个成员函数中抛出的异常的类型。如果异常的类型是Error或 RuntimeException, 或它们的子类,这个规则不起作用, 因为这在程序的正常部分中是不期待出现的。 如果你想明确地抛出一个RuntimeException,你必须用throws语句来声明它的类型
throw语句
throw总是出现在函数体中,用来抛出一个异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
其实,我个人觉得,简单的来说:throws与throw从拼写上只相差一个s,但是功能、作用上有很大的区别。throws用于在方法和类处声明可能抛出的所有异常信息。throw而throw就是单个语句抛出异常,是指抛出的一个具体的异常类型,使用在方法(类)的内部。
如:
………………………………………………………………………………………………………
public class showUI throws Exception(){
public void tbstudy throws Exception(){
****;//
try{
/* 这里是要处理的异常 */
}
Catch(Exception of){
System.out.println(of);//打印出异常
}
}
}
………………………………………………………………………………………………………
throws通常不用显示的捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法(即调用该方法或类的所有地方);
throw则需要用户自己捕获相关的异常,而后再对其进行相关处理(如打印异常的地方,类型等),最后将处理后的异常信息抛出。
他们对异常处理方式也不同.throws对异常不处理,谁调用谁处理,throws的Exception的取值范围要大于方法内部异常的最大范围,而cathch的范围又要大于throws的Exception的范围;throw 主动抛出自定义异常类对象。
二、异常继承体系
异常的继承结构
三、java处理异常方式
在java代码中如果发生异常,jvm(java虚拟机)会抛出异常对象,导致程序代码中断,这个时候jvm在做的操作就是:创建异常对象,然后抛出,比如:
1.int i= 1;
2.int j = 0;
3.int res = 0;
4.res = i/j;//除0错误
5.System.out.println(res);
这5句代码运行到第四句会中断,因为jvm抛出了异常
2.throw的作用:手动抛出异常。有时候有些错误在jvm看来不是错误,比如:
1. int age = 0;
2. age = -100;
3.System.out.println(age);
很正常的整形变量赋值,但是在我们眼中看来就不正常,谁的年龄会是负的呢?!所以我们需要自己手动引发异常,这就是throw的作用
int age = 0;
age = -100;
if(age<0){
Exception e = new Exception(); //创建异常对象
throw e; //抛出异常
}
System.out.println(age);
java中的异常机制
异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。
传统的处理异常的办法是,函数返回一个特殊的结果来表示出现异常(通常这个特殊结果是大家约定俗称的),调用该函数的程序负责检查并分析函数返回的结果。这样做有如下的弊端:例如函数返回-1代表出现异常,但是如果函数确实要返回-1这个正确的值时就会出现混淆;可读性降低,将程序代码与处理异常的代码混叠在一起;由调用函数的程序来分析错误,这就要求客户程序员对库函数有很深的了解。
在使用File类的方法时,如正在将U盘里面的照片复制到电脑里时,有人将U盘拔掉了。这时我们的复制程序就会出错,即抛出异常。当出现程序无法控制的外部环境问题(用户提供的文件不存在或者创建文件时已有同名文件存在,文件内容损坏,网络不可用...)时,JAVA就会用异常对象来描述。
异常情况通常有三大类:
(1)检查性异常:java.lang.Exception
(2)运行期异常:java.lang.RuntimeException
(3)错误:java.lang.Error
它们都是java.lang.Throwable类的子孙类。如右图:
Throwable 类是 Java 语言中所有错误和异常类的父类,对于具体的异常,不应该使用Throwable类,而应该使用其他三者之一。
检查性异常------程序正确,但因为外在的环境条件不满足引发。例如:用户错误及I/O问题----程序试图打开一个并不存在的远程Socket端口。这不是程序本身的逻辑错误,而很可能是远程机器名字错误(用户拼写错误)。对商用软件系统,程序开发者必须考虑并处理这个问题。JAVA编译器强制要求处理这类异常,如果不捕获这类异常,程序将不能被编译。
运行期异常------这意味着程序存在bug,如数组越界,0被除,入参不满足规范.....这类异常需要更改程序来避免,JAVA编译器强制要求处理这类异常。用来表示设计或实现方面的问题,如数组越界等。因为设计和实现正确的程序不会引发这类异常,所以常常不处理它。发生这类异常时,运行时环境会输出一条信息,提示用户修正错误。
错误------一般很少见,也很难通过程序解决。它可能源于程序的bug,但一般更可能源于环境问题,如内存耗尽。错误在程序中无须处理,而有运行环境处理。Error表示很难恢复的错误,如内存越界。一般不期望用户程序来处理,即使程序员有能力处理这种错误,也还是交给系统处理为好。
㈤ java 目前市面上比较火的框架有哪些
Java 始终排在第一位,这使它成为有史以来最着名的软件编程语言之一。及时的更新和新版本发布使它成为一种充满活力的、有竞争力的编程语言。
2020年最常用的java框架
十大常用框架:
一、SpringMVC
二、Spring
三、Mybatis
四、Dubbo
五、Maven
六、RabbitMQ
七、Log4j
八、Ehcache
九、Redis
十、Shiro
一、SpringMVC
Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。
模型(Model )封装了应用程序的数据和一般他们会组成的POJO。
视图(View)是负责呈现模型数据和一般它生成的HTML输出,客户端的浏览器能够解释。
控制器(Controller )负责处理用户的请求,并建立适当的模型,并把它传递给视图渲染。
Spring的web模型 - 视图 - 控制器(MVC)框架是围绕着处理所有的HTTP请求和响应的DispatcherServlet的设计。
Spring Web MVC处理请求的流程
具体执行步骤如下:
1、 首先用户发送请求————>前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分;图2-1中的1、2步骤;
2、 页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在Spring Web MVC中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理;处理完毕后返回一个ModelAndView(模型数据和逻辑视图名);图2-1中的3、4、5步骤;
3、 前端控制器收回控制权,然后根据返回的逻辑视图名,选择相应的视图进行渲染,并把模型数据传入以便视图渲染;图2-1中的步骤6、7;
4、 前端控制器再次收回控制权,将响应返回给用户,图2-1中的步骤8;至此整个结束。
二、Spring
2.1、IOC容器:
IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IOC容器进行组装。在Spring中BeanFactory是IOC容器的实际代表者。
2.2、AOP:
简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系
AOP用来封装横切关注点,具体可以在下面的场景中使用:
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading懒加载
Debugging 调试
logging, tracing, profiling and monitoring记录跟踪优化校准
Performance optimization性能优化
Persistence 持久化
Resource pooling资源池
Synchronization同步
Transactions 事务
三、Mybatis
MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
总体流程:
(1)加载配置并初始化
触发条件:加载配置文件
将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
(2)接收调用请求
触发条件:调用Mybatis提供的API
传入参数:为SQL的ID和传入参数对象
处理过程:将请求传递给下层的请求处理层进行处理。
(3)处理操作请求
触发条件:API接口层传递请求过来
传入参数:为SQL的ID和传入参数对象
处理过程:
(A)根据SQL的ID查找对应的MappedStatement对象。
(B)根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。
©获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果。
(D)根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
(E)释放连接资源。
(4)返回处理结果将最终的处理结果返回
MyBatis 最强大的特性之一就是它的动态语句功能。如果您以前有使用JDBC或者类似框架的经历,您就会明白把SQL语句条件连接在一起是多么的痛苦,要确保不能忘记空格或者不要在columns列后面省略一个逗号等。动态语句能够完全解决掉这些痛苦。
四、Dubbo
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC(远程过程调用协议)远程服务调用方案,以及SOA服务治理方案。简单的说,bbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有bbo这样的分布式服务框架的需求,并且本质上是个服务调用的东东,说白了就是个远程服务调用的分布式框架。
1、透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
2、软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3、 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
节点角色说明:
Provider: 暴露服务的服务提供方。
Consumer: 调用远程服务的服务消费方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次调和调用时间的监控中心。
Container: 服务运行容器。
五、Maven
Maven这个个项目管理和构建自动化工具,越来越多的开发人员使用它来管理项目中的jar包。但是对于我们程序员来说,我们最关心的是它的项目构建功能。
六、RabbitMQ
消息队列一般是在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。
RabbitMQ是用Erlang实现的一个高并发高可靠AMQP消息队列服务器。
Erlang是一门动态类型的函数式编程语言。对应到Erlang里,每个Actor对应着一个Erlang进程,进程之间通过消息传递进行通信。相比共享内存,进程间通过消息传递来通信带来的直接好处就是消除了直接的锁开销(不考虑Erlang虚拟机底层实现中的锁应用)。
AMQP(Advanced Message Queue Protocol)定义了一种消息系统规范。这个规范描述了在一个分布式的系统中各个子系统如何通过消息交互。
七、Log4j
日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。
八、Ehcache
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。
优点:
1、 快速
2、 简单
3、 多种缓存策略
4、缓存数据有两级:内存和磁盘,因此无需担心容量问题
5、 缓存数据会在虚拟机重启的过程中写入磁盘
6、可以通过RMI、可插入API等方式进行分布式缓存
7、 具有缓存和缓存管理器的侦听接口
8、支持多缓存管理器实例,以及一个实例的多个缓存区域
9、提供Hibernate的缓存实现
缺点:
1、使用磁盘Cache的时候非常占用磁盘空间:这是因为DiskCache的算法简单,该算法简单也导致Cache的效率非常高。它只是对元素直接追加存储。因此搜索元素的时候非常的快。如果使用DiskCache的,在很频繁的应用中,很快磁盘会满。
2、不能保证数据的安全:当突然kill掉java的时候,可能会产生冲突,EhCache的解决方法是如果文件冲突了,则重建cache。这对于Cache数据需要保存的时候可能不利。当然,Cache只是简单的加速,而不能保证数据的安全。如果想保证数据的存储安全,可以使用Bekeley DB Java Edition版本。这是个嵌入式数据库。可以确保存储安全和空间的利用率。
九、Redis
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis数据库完全在内存中,使用磁盘仅用于持久性。相比许多键值数据存储,Redis拥有一套较为丰富的数据类型。Redis可以将数据复制到任意数量的从服务器。
1.2、Redis优点:
(1)异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录。
(2)支持丰富的数据类型:Redis支持最大多数开发人员已经知道像列表,集合,有序集合,散列数据类型。这使得它非常容易解决各种各样的问题,因为我们知道哪些问题是可以处理通过它的数据类型更好。
(3)操作都是原子性:所有Redis操作是原子的,这保证了如果两个客户端同时访问的Redis服务器将获得更新后的值。
(4)多功能实用工具:Redis是一个多实用的工具,可以在多个用例如缓存,消息,队列使用(Redis原生支持发布/订阅),任何短暂的数据,应用程序,如Web应用程序会话,网页命中计数等。
1.3、Redis缺点:
(1)单线程
(2)耗内存
十、Shiro
Apache Shiro是Java的一个安全框架,旨在简化身份验证和授权。Shiro在JavaSE和JavaEE项目中都可以使用。它主要用来处理身份认证,授权,企业会话管理和加密等。Shiro的具体功能点如下:
(1)身份认证/登录,验证用户是不是拥有相应的身份;
(2)授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
(3)会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
(4)加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
(5)Web支持,可以非常容易的集成到Web环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
(6)shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
(7)提供测试支持;
(8)允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
(9)记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。
文字描述可能并不能让猿友们完全理解具体功能的意思。下面我们以登录验证为例,向猿友们介绍Shiro的使用。至于其他功能点,猿友们用到的时候再去深究其用法也不迟。
十一、设计模式
这个算不上框架,可自行忽略,不过我认为设计模式的思想很有必要了解一下。
思想:
开闭原则:
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码。
针对接口编程,针对接口编程,依赖于抽象而不依赖于具体。
尽量使用合成/聚合的方式,而不是使用继承。
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
使用多个隔离的接口,比使用单个接口要好。
里氏代换原则:
(1)子类的能力必须大于等于父类,即父类可以使用的方法,子类都可以使用。
(2)返回值也是同样的道理。假设一个父类方法返回一个List,子类返回一个ArrayList,这当然可以。如果父类方法返回一个ArrayList,子类返回一个List,就说不通了。这里子类返回值的能力是比父类小的。
(3)还有抛出异常的情况。任何子类方法可以声明抛出父类方法声明异常的子类。 而不能声明抛出父类没有声明的异常。
㈥ 在java中,异常处理的机制有哪几种,分别是什么
1 引子
try…catch…finally恐怕是大家再熟悉不过的语句了,而且感觉用起来也是很简单,逻辑上似乎也是很容易理解。不过,我亲自体验的“教训”告诉我,这个东西可不是想象中的那么简单、听话。不信?那你看看下面的代码,“猜猜”它执行后的结果会是什么?不要往后看答案、也不许执行代码看真正答案哦。如果你的答案是正确,那么这篇文章你就不用浪费时间看啦。
package myExample.testException;
public class TestException {
public TestException() {
}
boolean testEx() throws Exception{
boolean ret = true;
try{
ret = testEx1();
}catch (Exception e){
System.out.println("testEx, catch exception");
ret = false;
throw e;
}finally{
System.out.println("testEx, finally; return value="+ret);
return ret;
}
}
boolean testEx1() throws Exception{
boolean ret = true;
try{
ret = testEx2();
if (!ret){
return false;
}
System.out.println("testEx1, at the end of try");
return ret;
}catch (Exception e){
System.out.println("testEx1, catch exception");
ret = false;
throw e;
}
finally{
System.out.println("testEx1, finally; return value="+ret);
return ret;
}
}
boolean testEx2() throws Exception{
boolean ret = true;
try{
int b=12;
int c;
for (int i=2;i>=-2;i--){
c=b/i;
System.out.println("i="+i);
}
return true;
}catch (Exception e){
System.out.println("testEx2, catch exception");
ret = false;
throw e;
}
finally{
System.out.println("testEx2, finally; return value="+ret);
return ret;
}
}
public static void main(String[] args) {
TestException testException1 = new TestException();
try{
testException1.testEx();
}catch(Exception e){
e.printStackTrace();
}
}
}
你的答案是什么?是下面的答案吗?
i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, catch exception
testEx1, finally; return value=false
testEx, catch exception
testEx, finally; return value=false
如果你的答案真的如上面所说,那么你错啦。^_^,那就建议你仔细看一看这篇文章或者拿上面的代码按各种不同的情况修改、执行、测试,你会发现有很多事情不是原来想象中的那么简单的。
现在公布正确答案:
i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, finally; return value=false
testEx, finally; return value=false
2 基础知识
2.1 相关概念
例外是在程序运行过程中发生的异常事件,比如除0溢出、数组越界、文件找不到等,这些事件的发生将阻止程序的正常运行。为了加强程序的鲁棒性,程序设计时,必须考虑到可能发生的异常事件并做出相应的处理。C语言中,通过使用if语句来判断是否出现了例外,同时,调用函数通过被调用函数的返回值感知在被调用函数中产生的例外事件并进行处理。全程变量ErroNo常常用来反映一个异常事件的类型。但是,这种错误处理机制会导致不少问题。
Java通过面向对象的方法来处理例外。在一个方法的运行过程中,如果发生了例外,则这个方法生成代表该例外的一个对象,并把它交给运行时系统,运行时系统寻找相应的代码来处理这一例外。我们把生成例外对象并把它提交给运行时系统的过程称为抛弃(throw)一个例外。运行时系统在方法的调用栈中查找,从生成例外的方法开始进行回朔,直到找到包含相应例外处理的方法为止,这一个过程称为捕获(catch)一个例外。
2.2 Throwable类及其子类
用面向对象的方法处理例外,就必须建立类的层次。类 Throwable位于这一类层次的最顶层,只有它的后代才可以做为一个例外被抛弃。图1表示了例外处理的类层次。
从图中可以看出,类Throwable有两个直接子类:Error和Exception。Error类对象(如动态连接错误等),由Java虚拟机生成并抛弃(通常,Java程序不对这类例外进行处理);Exception类对象是Java程序处理或抛弃的对象。它有各种不同的子类分别对应于不同类型的例外。其中类RuntimeException代表运行时由Java虚拟机生成的例外,如算术运算例外ArithmeticException(由除0错等导致)、数组越界例外等;其它则为非运行时例外,如输入输出例外IOException等。Java编译器要求Java程序必须捕获或声明所有的非运行时例外,但对运行时例外可以不做处理。
图1 例外处理的类层次
2.3 异常处理关键字
Java的异常处理是通过5个关键字来实现的:try,catch,throw,throws,finally。JB的在线帮助中对这几个关键字是这样解释的:
Throws: Lists the exceptions a method could throw.
Throw: Transfers control of the method to the exception handler.
Try: Opening exception-handling statement.
Catch: Captures the exception.
Finally: Runs its code before terminating the program.
2.3.1 try语句
try语句用大括号{}指定了一段代码,该段代码可能会抛弃一个或多个例外。
2.3.2 catch语句
catch语句的参数类似于方法的声明,包括一个例外类型和一个例外对象。例外类型必须为Throwable类的子类,它指明了catch语句所处理的例外类型,例外对象则由运行时系统在try所指定的代码块中生成并被捕获,大括号中包含对象的处理,其中可以调用对象的方法。
catch语句可以有多个,分别处理不同类的例外。Java运行时系统从上到下分别对每个catch语句处理的例外类型进行检测,直到找到类型相匹配的catch语句为止。这里,类型匹配指catch所处理的例外类型与生成的例外对象的类型完全一致或者是它的父类,因此,catch语句的排列顺序应该是从特殊到一般。
也可以用一个catch语句处理多个例外类型,这时它的例外类型参数应该是这多个例外类型的父类,程序设计中要根据具体的情况来选择catch语句的例外处理类型。
2.3.3 finally语句
try所限定的代码中,当抛弃一个例外时,其后的代码不会被执行。通过finally语句可以指定一块代码。无论try所指定的程序块中抛弃或不抛弃例外,也无论catch语句的例外类型是否与所抛弃的例外的类型一致,finally所指定的代码都要被执行,它提供了统一的出口。通常在finally语句中可以进行资源的清除工作。如关闭打开的文件等。
2.3.4 throws语句
throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常。对大多数Exception子类来说,Java 编译器会强迫你声明在一个成员函数中抛出的异常的类型。如果异常的类型是Error或 RuntimeException, 或它们的子类,这个规则不起作用, 因为这在程序的正常部分中是不期待出现的。 如果你想明确地抛出一个RuntimeException,你必须用throws语句来声明它的类型。
2.3.5 throw语句
throw总是出现在函数体中,用来抛出一个异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
3 关键字及其中语句流程详解
3.1 try的嵌套
你可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部,写另一个try语句保护其他代码。每当遇到一个try语句,异常的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,堆栈就会展开,直到遇到有处理这种异常的try语句。下面是一个try语句嵌套的例子。
class MultiNest {
static void procere() {
try {
int a = 0;
int b = 42/a;
} catch(java.lang.ArithmeticException e) {
System.out.println("in procere, catch ArithmeticException: " + e);
}
}
public static void main(String args[]) {
try {
procere();
} catch(java.lang. Exception e) {
System.out.println("in main, catch Exception: " + e);
}
}
}
这个例子执行的结果为:
in procere, catch ArithmeticException: java.lang.ArithmeticException: / by zero
成员函数procere里有自己的try/catch控制,所以main不用去处理 ;当然如果如同最开始我们做测试的例子一样,在procere中catch到异常时使用throw e;语句将异常抛出,那么main当然还是能够捕捉并处理这个procere抛出来的异常。例如在procere函数的catch中的System.out语句后面增加throw e;语句之后,执行结果就变为:
in procere, catch ArithmeticException: java.lang.ArithmeticException: / by zero
in main, catch Exception: java.lang.ArithmeticException: / by zero
3.2 try-catch程序块的执行流程以及执行结果
相对于try-catch-finally程序块而言,try-catch的执行流程以及执行结果还是比较简单的。
首先执行的是try语句块中的语句,这时可能会有以下三种情况:
1. 如果try块中所有语句正常执行完毕,那么就不会有其他的“动做”被执行,整个try-catch程序块正常完成。
2. 如果try语句块在执行过程中碰到异常V,这时又分为两种情况进行处理:
² 如果异常V能够被与try相应的catch块catch到,那么第一个catch到这个异常的catch块(也是离try最近的一个与异常V匹配的catch块)将被执行;如果catch块执行正常,那么try-catch程序块的结果就是“正常完成”;如果该catch块由于原因R突然中止,那么try-catch程序块的结果就是“由于原因R突然中止(completes abruptly)”。
² 如果异常V没有catch块与之匹配,那么这个try-catch程序块的结果就是“由于抛出异常V而突然中止(completes abruptly)”。
3. 如果try由于其他原因R突然中止(completes abruptly),那么这个try-catch程序块的结果就是“由于原因R突然中止(completes abruptly)”。
3.3 try-catch-finally程序块的执行流程以及执行结果
try-catch-finally程序块的执行流程以及执行结果比较复杂。
首先执行的是try语句块中的语句,这时可能会有以下三种情况:
1. 如果try块中所有语句正常执行完毕,那么finally块的居于就会被执行,这时分为以下两种情况:
² 如果finally块执行顺利,那么整个try-catch-finally程序块正常完成。
² 如果finally块由于原因R突然中止,那么try-catch-finally程序块的结局是“由于原因R突然中止(completes abruptly)”
2. 如果try语句块在执行过程中碰到异常V,这时又分为两种情况进行处理:
² 如果异常V能够被与try相应的catch块catch到,那么第一个catch到这个异常的catch块(也是离try最近的一个与异常V匹配的catch块)将被执行;这时就会有两种执行结果:
² 如果catch块执行正常,那么finally块将会被执行,这时分为两种情况:
² 如果finally块执行顺利,那么整个try-catch-finally程序块正常完成。
² 如果finally块由于原因R突然中止,那么try-catch-finally程序块的结局是“由于原因R突然中止(completes abruptly)”
² 如果catch块由于原因R突然中止,那么finally模块将被执行,分为两种情况:
² 如果如果finally块执行顺利,那么整个try-catch-finally程序块的结局是“由于原因R突然中止(completes abruptly)”。
² 如果finally块由于原因S突然中止,那么整个try-catch-finally程序块的结局是“由于原因S突然中止(completes abruptly)”,原因R将被抛弃。
(注意,这里就正好和我们的例子相符合,虽然我们在testEx2中使用throw e抛出了异常,但是由于testEx2中有finally块,而finally块的执行结果是complete abruptly的(别小看这个用得最多的return,它也是一种导致complete abruptly的原因之一啊——后文中有关于导致complete abruptly的原因分析),所以整个try-catch-finally程序块的结果是“complete abruptly”,所以在testEx1中调用testEx2时是捕捉不到testEx1中抛出的那个异常的,而只能将finally中的return结果获取到。
如果在你的代码中期望通过捕捉被调用的下级函数的异常来给定返回值,那么一定要注意你所调用的下级函数中的finally语句,它有可能会使你throw出来的异常并不能真正被上级调用函数可见的。当然这种情况是可以避免的,以testEx2为例:如果你一定要使用finally而且又要将catch中throw的e在testEx1中被捕获到,那么你去掉testEx2中的finally中的return就可以了。
这个事情已经在OMC2.0的MIB中出现过啦:服务器的异常不能完全被反馈到客户端。)
² 如果异常V没有catch块与之匹配,那么finally模块将被执行,分为两种情况:
² 如果finally块执行顺利,那么整个try-catch-finally程序块的结局就是“由于抛出异常V而突然中止(completes abruptly)”。
² 如果finally块由于原因S突然中止,那么整个try-catch-finally程序块的结局是“由于原因S突然中止(completes abruptly)”,异常V将被抛弃。
3. 如果try由于其他原因R突然中止(completes abruptly),那么finally块被执行,分为两种情况:
² 如果finally块执行顺利,那么整个try-catch-finally程序块的结局是“由于原因R突然中止(completes abruptly)”。
² 如果finally块由于原因S突然中止,那么整个try-catch-finally程序块的结局是“由于原因S突然中止(completes abruptly)”,原因R将被抛弃。
3.4 try-catch-finally程序块中的return
从上面的try-catch-finally程序块的执行流程以及执行结果一节中可以看出无论try或catch中发生了什么情况,finally都是会被执行的,那么写在try或者catch中的return语句也就不会真正的从该函数中跳出了,它的作用在这种情况下就变成了将控制权(语句流程)转到finally块中;这种情况下一定要注意返回值的处理。
例如,在try或者catch中return false了,而在finally中又return true,那么这种情况下不要期待你的try或者catch中的return false的返回值false被上级调用函数获取到,上级调用函数能够获取到的只是finally中的返回值,因为try或者catch中的return语句只是转移控制权的作用。
3.5 如何抛出异常
如果你知道你写的某个函数有可能抛出异常,而你又不想在这个函数中对异常进行处理,只是想把它抛出去让调用这个函数的上级调用函数进行处理,那么有两种方式可供选择:
第一种方式:直接在函数头中throws SomeException,函数体中不需要try/catch。比如将最开始的例子中的testEx2改为下面的方式,那么testEx1就能捕捉到testEx2抛出的异常了。
boolean testEx2() throws Exception{
boolean ret = true;
int b=12;
int c;
for (int i=2;i>=-2;i--){
c=b/i;
System.out.println("i="+i);
}
return true;
}
第二种方式:使用try/catch,在catch中进行一定的处理之后(如果有必要的话)抛出某种异常。例如上面的testEx2改为下面的方式,testEx1也能捕获到它抛出的异常:
boolean testEx2() throws Exception{
boolean ret = true;
try{
int b=12;
int c;
for (int i=2;i>=-2;i--){
c=b/i;
System.out.println("i="+i);
}
return true;
}catch (Exception e){
System.out.println("testEx2, catch exception");
Throw e;
}
}
第三种方法:使用try/catch/finally,在catch中进行一定的处理之后(如果有必要的话)抛出某种异常。例如上面的testEx2改为下面的方式,testEx1也能捕获到它抛出的异常:
boolean testEx2() throws Exception{
boolean ret = true;
try{
int b=12;
int c;
for (int i=2;i>=-2;i--){
c=b/i;
System.out.println("i="+i);
throw new Exception("aaa");
}
return true;
}catch (java.lang.ArithmeticException e){
System.out.println("testEx2, catch exception");
ret = false;
throw new Exception("aaa");
}finally{
System.out.println("testEx2, finally; return value="+ret);
}
}
4 关于abrupt completion
前面提到了complete abruptly(暂且理解为“突然中止”或者“异常结束”吧),它主要包含了两种大的情形:abrupt completion of expressions and statements,下面就分两种情况进行解释。
4.1 Normal and Abrupt Completion of Evaluation
每一个表达式(expression)都有一种使得其包含的计算得以一步步进行的正常模式,如果每一步计算都被执行且没有异常抛出,那么就称这个表达式“正常结束(complete normally)”;如果这个表达式的计算抛出了异常,就称为“异常结束(complete abruptly)”。异常结束通常有一个相关联的原因(associated reason),通常也就是抛出一个异常V。
与表达式、操作符相关的运行期异常有:
² A class instance creation expression, array creation expression , or string concatenation operatior expression throws an OutOfMemoryError if there is insufficient memory available.
² An array creation expression throws a NegativeArraySizeException if the value of any dimension expression is less than zero.
² A field access throws a NullPointerException if the value of the object reference expression is null.
² A method invocation expression that invokes an instance method throws a NullPointerException if the target reference is null.
² An array access throws a NullPointerException if the value of the array reference expression is null.
² An array access throws an if the value of the array index expression is negative or greater than or equal to the length of the array.
² A cast throws a ClassCastException if a cast is found to be impermissible at run time.
² An integer division or integer remainder operator throws an ArithmeticException if the value of the right-hand operand expression is zero.
² An assignment to an array component of reference type throws an ArrayStoreException when the value to be assigned is not compatible with the component type of the array.
4.2 Normal and Abrupt Completion of Statements
正常情况我们就不多说了,在这里主要是列出了abrupt completion的几种情况:
² break, continue, and return 语句将导致控制权的转换,从而使得statements不能正常地、完整地执行。
² 某些表达式的计算也可能从java虚拟机抛出异常,这些表达式在上一小节中已经总结过了;一个显式的的throw语句也将导致异常的抛出。抛出异常也是导致控制权的转换的原因(或者说是阻止statement正常结束的原因)。
如果上述事件发生了,那么这些statement就有可能使得其正常情况下应该都执行的语句不能完全被执行到,那么这些statement也就是被称为是complete abruptly.
导致abrupt completion的几种原因:
² A break with no label
² A break with a given label
² A continue with no label
² A continue with a given label
² A return with no value
² A return with a given value A
² throw with a given value, including exceptions thrown by the Java virtual machine
5 关于我们的编程的一点建议
弄清楚try-catch-finally的执行情况后我们才能正确使用它。
如果我们使用的是try-catch-finally语句块,而我们又需要保证有异常时能够抛出异常,那么在finally语句中就不要使用return语句了(finally语句块的最重要的作用应该是释放申请的资源),因为finally中的return语句会导致我们的throw e被抛弃,在这个try-catch-finally的外面将只能看到finally中的返回值(除非在finally中抛出异常)。(我们需要记住:不仅throw语句是abrupt completion 的原因,return、break、continue等这些看起来很正常的语句也是导致abrupt completion的原因。)