文章目录
一. 异常分类
Throwable
类是Java所有异常和错误的基类,其子类分为两大类,分别是异常(Exception
)和错误(Error
)
Exception
非致命异常。程序可处理。分为受编译器检测的
checked
异常(受检异常)和不受编译器检测的unchecked
异常(非受检异常)。
-
checked exceptions
-
非运行时异常 (编译异常)
-
编译器会强制在编译时对异常进行捕获或声明,可以用
try-catch
捕获 -
如:IOException,SQLException等
-
-
unchecked exceptions
- 运行时异常,RuntimeException 类及其子类异常
- 测试时程序终止,控制台出现异常,不建议捕获
- 如:NullPointerException,IndexOutOfBoundsException等
RunTimeException
- ArithmeticException 类
public class Test {
public static void main(String[] args) {
try{
int a,b,c;
a=1;
b=0;
c=a/b;
System.out.println(c);
}
catch(ArithmeticException ae){
ae.printStackTrace();
System.out.println("算术异常");
}
}
}
- NullPointerException 类
public class Test {
private static int[] x;
public static void main(String[] args) {
try {
System.out.println(x[0]);
}
catch(NullPointerException ne) {
ne.printStackTrace();
System.out.println("空指针异常");
}
}
}
- ArrayIndexOutOfBoundsException 类
public class Test {
public static void main(String[] args) {
try{
String foo=args[1];
System.out.println("foo="+foo);
}
catch(ArrayIndexOutOfBoundsException ae) {
ae.printStackTrace();
System.out.println("数组下标越界");
}
}
}
- ClassCastException 类
class Father{}
class Son extends Father{}
public class Test{
public static void main(String args[]){
try{
Father father = new Father();
Son son = (Son) father;
}
catch(ClassCastException ce){
ce.printStackTrace();
System.out.println("类型强制转换异常");
}
}
}
- NegativeArraySizeException 类
public class Test {
public static void main(String[] args) {
try{
int[] a;
a=new int[-1];
}
catch(NegativeArraySizeException ne) {
ne.printStackTrace();
System.out.println("数组下标负数异常");
}
}
}
Error
致命异常。标识系统发生了不可控的错误。程序无法处理,只能人工介入。
- 由Java虚拟机生成并抛出,程序基本不可以通过后续代码修复,从而理应终止
- 如:VirtualMachineError,ThreadDeath等
StackOverflowError
栈溢出,虚拟机栈或本地方栈空间被耗尽,没有足够资源分配给新创建的栈帧
- 原因:
- 递归调用过深,没有跳出递归的条件
- 执行了大量方法,导致线程栈空间耗尽
- 不断创建线程
- 解决方法:
- 减少递归层数或调用方法层次
- 手动修改栈大小
OutOfMemoryError
内存溢出,程序运行过程中申请的内存大于系统能够提供的内存,导致无法申请到足够的内存
- 原因:
- 内存泄漏
- 在比较深的循环中创建对象
- 静态变量过多
- 解决方法:
- 减小内存申请空间
- 手动修改内存空间(栈或堆)大小参数,调整虚拟机启动参数
二. 异常处理
声明抛出处理
向调用方传播异常,自身不处理
- 显示声明抛出,
throws
语句
public class ExampleException {
public static void main(String[] args) throws ArithmeticException{
int a,b,c;
a=67; b=0;
c=a/b;
System.out.println(a+"/"+b+"="+c);
}
}
/*
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExampleException.main(ExampleException.java:6)
*/
- 隐式声明抛出,若是unchecked异常类型,则throws声明子句可省略
public class Test {
private static int[] x;
public static void main(String[] args){
System.out.println(x[0]);
}
}
/*
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:4)
*/
程序捕获处理
在当前方法捕获并处理异常
try-catch-finally
语句
public class Test {
public static int method() { // throws ArithmeticException 语句省略
int a,b,c;
a=67; b=0;
c=a/b;
return c;
}
public static void main(String[] args) {
try {
System.out.println(method());
}
catch(ArithmeticException ae){
ae.printStackTrace();
System.out.println("Arithmetic Error!");
}
finally {
System.out.println( "Finally" );
}
}
}
/*
java.lang.ArithmeticException: / by zero
at Test.method(Test.java:5)
at Test.main(Test.java:10)
Arithmetic Error!
Finally
*/
- finally 语句(可选)
- 作用:一般用来进行一些善后清理操作,例如清理资源、释放连接、关闭文件、管道流等操作。
三. throws vs throw
throws
函数方法抛出异常,一般写在方法的头部,用来抛出一些异常,本身不进行解决,抛给方法的调用者进行解决(try-catch)
class Example{
int a=25;
int b=0;
int c;
public int method() throws ArithmeticException{
c=a/b;
return c;
}
}
public class Test {
public static void main(String[] args){
Example ex = new Example();
try{
System.out.println(ex.method());
}
catch(ArithmeticException ae){
ae.printStackTrace();
}
}
}
/*
java.lang.ArithmeticException: / by zero
at Example.method(Test.java:6)
at Test.main(Test.java:15)
*/
throw
语句抛出异常,出现于函数内部,用来抛出一个具体异常实例,throw被执行后,后面的语句不起作用,直接转入异常处理阶段
class Example{
int a=25;
int b=0;
int c;
public void method(){
c=a/b;
}
}
public class Test {
public static void main(String[] args){
Example ex = new Example();
try{
ex.method();
throw new ArithmeticException();
//System.out.println("Try"); java: 无法访问的语句
}
catch(ArithmeticException ae){
ae.printStackTrace();
}
}
}
/*
java.lang.ArithmeticException: / by zero
at Example.method(Test.java:6)
at Test.main(Test.java:14)
*/
四. 自定义异常类应用
class SelfException extends Exception {
private int id;
public SelfException(String msg, int id) {
super(msg);
this.id = id;//调用Exception的构造方法
}
public int getId() {
return id;
}
}
public class Test{
public static void checkId(int id) throws SelfException{
if(id < 0){
throw new SelfException("id不能为负值", id);
}else if(id>1500){
throw new SelfException("id超出范围", id);
}else{
System.out.println("id正确");
}
}
public static void main(String args[]){
try{
checkId(10000);
}
catch(SelfException se){
se.printStackTrace();
System.out.println("id=" + se.getId() + " 不正确");
}
}
}
/*
SelfException: id超出范围
at Test.checkId(Test.java:19)
at Test.main(Test.java:27)
id=10000不正确
*/
总结
从简单认识异常分类到对异常进行捕获并处理的应用逐渐了解Java异常处理机制,通过对异常的处理,可以使程序更为完善,考虑到尽可能多的特殊情况,增强容错率,是以后软件开发中不可缺少的环节
在整理博客的过程中参考了一些资料以及许多他人优秀的文章,就不一一列举,在此表示感谢。