异常的定义
异常就是有异于常态,和正常情况不一样,有错误出现。在java中,阻止当前方法或作用域的情况,称之为异常。
异常的分类
Error:是程序中无法处理的错误,表示运行应用程序中出现了严重的错误。此类错误一般表示代码运行时JVM出现问题。通常有Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。比如说当jvm耗完可用内存时,将出现OutOfMemoryError。此类错误发生时,JVM将终止线程。非代码性错误。因此,当此类错误发生时,应用不应该去处理此类错误。
在Java虚拟机规范中描述了两种异常:
定义: 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemory Error异常。
这里把异常分成两种情况,看似更加严谨,但却存在着一些互相重叠的地方:当栈空间
无法继续分配时,到底是内存太小,还是已使用的栈空间太大,其本质上只是对同一件事情
的两种描述而已
Exception::程序本身可以捕获并且可以处理的异常。
运行时异常(不受检异常):RuntimeException类极其子类表示JVM在运行期间可能出现的错误。编译器不会检查此类异常,并且不要求处理异常,比如用空值对象的引用(NullPointerException)、数组下标越界(ArrayIndexOutBoundException)。此类异常属于不可查异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。
非运行时异常(受检异常):Exception中除RuntimeException极其子类之外的异常。编译器会检查此类异常,如果程序中出现此类异常,比如说IOException,必须对该异常进行处理,要么使用try-catch捕获,要么使用throws语句抛出,否则编译不通过。
异常的处理
抛出异常:throw,throws
捕获异常:try,catch,finally
抛出异常throw
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结 束当前方法的执行。
使用的格式:
throw new 异常类名(参数);
编译器会处理runtimeException,不用捕获或抛出。
public class DemoThrow { public static void main(String[] args) { int a = DemoThrow.div(4,0); System.out.println(a); } public static int div(int a,int b) { if(b==0) throw new ArithmeticException("异常信息:除数不能为0");//抛出具体问题,编译时不检测 return a/b; } }
声明抛出异常throws
运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常
使用格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2 ... { }
public class DemoThrows { public static void main(String[] args) throws FileNotFoundException{ readFile(); } public static void readFile() throws FileNotFoundException { InputStream is = new FileInputStream("E:/iodemo/ch01.txt"); }
try代码块
try { ... //监视代码执行过程,一旦返现异常则直接跳转至catch, // 如果没有异常则直接跳转至finally } catch (SomeException e) { ... //可选执行的代码块,如果没有任何异常发生则不会执行; //如果发现异常则进行处理或向上抛出。 } finally { ... //必选执行的代码块,不管是否有异常发生, // 即使发生内存溢出异常也会执行,通常用于处理善后清理工作。 }
自定义异常
除了JDK定义好的异常类外,在开发过程中根据业务的异常情况自定义异常类。
/** * 自定义异常类 * 用户不存在异常信息类 */ public class UserNotExistsException extends RuntimeException{ public UserNotExistsException() { super(); } public UserNotExistsException(String message) { super(message); } }
编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设。
可以将断言看作是异常处理的一种高级形式。
断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真。
可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新起用断言。
使用断言可以创建更稳定,品质更好且易于除错的代码。
当需要在一个值为FALSE时中断当前操作的话,可以使用断言。
单元测试必须使用断言(Junit/JunitX)。
除了类型检查和单元测试外,断言还提供了一种确定个种特性是否在程序中得到维护的极好的方法。
使用断言使我们向按契约式设计更近了一步。
常见的断言特性:
前置条件断言:代码执行之前必须具备的特性
后置条件断言:代码执行之后必须具备的特性
前后不变断言:代码执行前后不能变化的特性
断言使用格式:
断言可以有两种形式
1.assert 布尔表达式
2.assert 布尔表达式:消息
使用第一种格式,当布尔类型表达式为false时,抛出AssertionError异常;如果是第二种格式,则输出错误消息。
断言的启用:
在默认情况下,断言不起作用,在eclipse等工具中可以开启和关闭断言功能,
选择菜单--Run--Run Configuration--Java Application--选择对应的类--Arguments--VM argument--填入-ea/-da
关于-ea(开启断言)和-da(关闭断言)的说明如下
java -ea 类名
java -ea:包名 -da:类名
选项-ea、-da用于激活和禁用断言。
如果选项不带任何参数,则表示激活或禁用所有用户类;
如果带有包名或类名,则表示激活或禁用这些类或包;
如果包名称后面跟有三个“.”,则表示这个包及子包;
如果只有三个“.”,则代表无包名。
案例:
public class TestAssertion{
public static void main(String[] args){
assert(1==0):"1和0不相等!";
}
}
开启断言后,运行结果,会报main方法的异常:1和0不相等!
何时需要使用断言:
1.可以在预计正常情况下程序不会到达的地方放置断言 :assert false;
2.断言可以用于检查传递给私有方法的参数。(对于公有方法,因为是提供给外部的接口,所以必须在方法中有相应的参数检验才能保证代码的健壮性);
3.使用断言测试方法执行的前置条件和后置条件;
4.使用断言检查类的不变状态,确保任何情况下,某个变量的状态必须满足。(如age属性应大于0小于某个合适值)。
什么地方不要使用断言:
断言语句不是永远会执行,可以屏蔽也可以启用
因此:
1.不要使用断言作为公共方法的参数检查,公共方法的参数永远都要执行;
2.断言语句不可以有任何边界效应,不要使用断言语句去修改变量和改变方法的返回值。
原文:https://www.cnblogs.com/baldprogrammer/p/13637384.html