学习java异常处理机制个人的一些理解

学习java已经比较久一段时间了,其实对于java异常这方面的知识只停留在javac让我throws一下或trycatch一下我就直接做了,其实并没有真的了解整个java的异常处理机制是怎样的,这几天就深入的去了解了异常处理机制,下面我讲一下对于java异常处理机制的一些个人的理解。

在讲之前我先说一下学异常的时候我觉得异常处理没什么用的想法。看一些异常的讲解,都说什么除0异常,文件不存在异常。那时我心里就在觉得挺奇怪的,既然有可能出现除0,那我加个判断不就可以了?既然文件可能不存在,那我也加个判断不就可以了?too young to simple,如果你也有我当时的疑惑,可以看下知乎的解答,这里就不过多阐述。

链接:https://www.zhihu.com/question/27122172

异常(Exception)

    异常是什么?不正常的事件。运行程序时,它没有按照我们的预期执行,也就是不正常的运作,就叫异常。

首先

当我们写java程序的时候,我们觉得这个地方可能会有异常(比如文件不存在),我们得怎么做?1.要么自己处理吧?(try、catch)2.要么抛出去给调用者处理吧?(throws)

其次

当我们写java程序的时候出现了异常,我们得知道异常的什么? 1.是什么异常得知道吧?(异常的分类) 2.异常出现在哪里得知道吧?(异常链)

java解决上面需求的,就是我们所说的java异常处理机制

我将从以下方面讲我所理解的java异常处理机制

1.异常类
2.异常处理语句及语法
3.异常链(异常栈)
4.常见异常
5.自定义异常

1.异常类

java中所有的事件、机制都由类描述,Java中的异常就是由java.lang包下的异常类描述的。

java异常类导图



这是我根据java官方文档用Xmind做的JDK8的异常类导图,可以看出java的异常都是继承Throwable父类的。

Throwable有派生出Error和Exception子类

Error:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it

A method is not required to declare in its throws clause any subclasses of Error that might be thrown during the execution of the method but not caught, since these errors are abnormal conditions that should never occur. That is, Error and its subclasses are regarded as unchecked exceptions for the purposes of compile-time checking of exceptions.

以上两段是官方文档对Error类的解释,简单来说就是这些错误都是不能试图去捕获或抛出,因为这些错误是不能被程序员通过代码去处理的,比如内存不足之类的,JVM本身错误等。Error类及其子类都是非检查异常。

Exception:

The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to catch.

The class Exception and any subclasses that are not also subclasses of RuntimeException are checked exceptions. Checked exceptions need to be declared in a method or constructor's throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary.

以上两段也是官方文档对Exception类的描述,大体上说就是可以让程序员通过代码去处理(try..catch / throws),并说明除了RuntimeException及其之类外的其他异常都是检查异常。

上面提到的非检查异常和检查异常:

非检查异常(unchecked exception):包括Error和RuntimeException以及他们的子类。java编译器在编译时,不会提示和发现这样的异常,不要求在程序预处理这些异常(比如不会在写程序时报小灯泡红叉标识要你trycatch或者throws)。当然如果你觉得可能会有异常就可以使用try..catch处理或throws抛出。

检查异常(checked exception):包括除了Error和RuntimeException的其他异常。java编译器强制要求程序员预处理(通过报小灯泡红叉要求你必须使用try..catch或throws)不然编译器就会报错不让你通过。

一般的,作为程序员的我们应该关注Exception类下的分支的异常。

以上便是自己对java异常类的一些理解以及分类的讲解。

2.异常处理语句及语法

在写代码处理异常的时候,有两种不同的处理方式:1.使用try..catch..finally处理. 2.使用throws声明抛给函数调用者去处理

1.try...catch..finally语句块
try{
     //1.存放可能发生异常的代码。
     //2.如果没有发生异常,执行finally块代码(如果有finally块)并往下执行代码,否则,直接尝试去匹配catch块。
 
}catch(IOException e1){
    //每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。
    //catch后面的括号定义了异常类型和异常参数(局部的)。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
    //在catch块中可以使用这个块的异常参数来获取异常的相关信息(getMessage()、printStackTrace()、getCause())。
}catch(Exception e2){
    //...
}finally{
    //finally块可要可不要。
   //一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
  //finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。 
}

需要注意的是:

1.try块发生异常,那么try块中发生异常的那一行以下的代码都不会执行。

2.无论异常发生与否,异常是否有catch匹配处理,finally块都会执行。

3.如果try..catch..中有return 先执行finally,再执行return

package test;

public class TestException3 {  
       
    public static void main(String args[]) { // 主方法  
    	TestException3 t=new TestException3();
    	int i=t.test();
    	System.out.println(i);
    }  
  
    public  int test(){
    	try {
    		int c=1/0;
    		return 0;
    	}catch(Exception e){
    		e.printStackTrace();
    		return 1;
    	}finally {
    		System.out.println("finally");
    	}
    }
}

运行结果:

java.lang.ArithmeticException: / by zero
	at test.TestException3.test(TestException3.java:16)
	at test.TestException3.main(TestException3.java:10)
finally
1

个人想法:catch块中的异常类型,其实我觉得直接就一个Exception就好啦,什么异常都直接捕获,就不用再细分可能出现什么异常了,一来代码简洁二来防止漏掉异常。

2.throws声明
    public void test2() throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN
    { 
         //函数内部可以抛出 ExceptionType1 , ExceptionType2 ,ExceptionTypeN 类的异常,或者他们的子类的异常对象。
    }

throws是另一种异常处理的方式,作用是将函数中可能出现的异常抛给调用者来处理(向调用者声明),自己不作处理。

一般使用throws有两种原因:

1.方法本身不知道如何处理这样的异常,或者说让调用者处理更好,调用者需要为可能发生的异常负责。

2.分层思想:比如web开发的service和dao层,在大部分情况下,dao服务于service,但这都属于开发组内部,所以,dao直接throw就可以了。但是到了service层,调用service的是另外的开发小组(比如客户端小组),从架构上来说,就需要隐藏代码的内部细节,这个时候就必须要catch掉。底层不处理,往上抛,上层去try catch然后去处理对应异常类型。再根据需求展示给用户。

3.异常链(异常栈)

Java这种向上传递异常信息的处理机制,形成异常链

异常链的概念我们用一段代码来理解就好了

package test;
public class TestException3 {  
    public static void main(String args[]) { // 主方法  
    		test1();
    }  
    public static  void test1(){
    	try {
    		test2();
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    }
    public static void test2(){
    	try {
    		test3();
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    }
    public static  void test3(){
    	try {
    		int c=1/0;
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    }
}  

运行结果:

java.lang.ArithmeticException: / by zero
	at test.TestException3.test3(TestException3.java:27)
	at test.TestException3.test2(TestException3.java:19)
	at test.TestException3.test1(TestException3.java:11)
	at test.TestException3.main(TestException3.java:6)

我写了三个测试函数,除0异常出现在test3,然后test2调用test3,test1调用test2,main函数调用test1。

从异常结果可以看出main函数调用了test1发生了异常,把异常位置压栈以此类推直到找出异常的真正位置,然后按栈先进后出依次输出。

官方的说法就是Java方法抛出的可查异常将依据调用栈、沿着方法调用的层次结构一直传递到具备处理能力的调用方法,最高层次到main方法为止。

4.常见异常

看了下面的异常,是不是觉得很熟悉,很想打人哈哈哈。

   1、 ArrayIndexOutOfBoundsException
    数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
   2、ArithmeticException
    算术条件异常。譬如:整数除零等。
   3、NullPointerException
    空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
   4、java.lang.ClassNotFoundException
    找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件就抛出该异常。
   5、java.lang.NegativeArraySizeException  数组长度为负异常
   6、java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常
   7、java.lang.SecurityException 安全性异常
   8、java.lang.IllegalArgumentException 非法参数异常
   9、IOException:操作输入流和输出流时可能出现的异常。
  10、EOFException   文件已结束异常
  11、FileNotFoundException   文件未找到异常
  12、ClassCastException    类型转换异常类
  13、ArrayStoreException  数组中包含不兼容的值抛出的异常
  14、SQLException   操作数据库异常类
  15、NoSuchFieldException   字段未找到异常
  16、NoSuchMethodException   方法未找到抛出的异常
  17、NumberFormatException    字符串转换为数字抛出的异常
  18、StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
  19、IllegalAccessException  不允许访问某类异常

  20、InstantiationException  当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常

5.自定义异常

除了用java内置的异常类异常,我们还可以自定义自己所需要的异常。方法也很简单

1.创建自己的异常类并写自己的异常处理代码

2.继承Exception类(extends Exception)

3.在异常发生处的catch块的异常类型中使用

package test;
public class ExceptionTest extends  Exception{  
   public void test(){
	   System.out.println("自定义异常");
   }
} 
package test;
public class TestException3 {  
    public static void main(String args[]) { // 主方法  
    	int i=1;
    	if(i==1) {
    		try {
				throw new ExceptionTest();
			} catch (ExceptionTest e) {
				e.test();
			}
    	}
    }
}

运行结果:自定义异常

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值