异常及处理"/>
Java异常及处理
一、Java异常概念及分类
1.1 异常简介
Java异常是Java提供的一种识别及响应错误的一致性机制。
Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序健壮性。在有效使用异常的情况下,异常能清晰的回答。
1.2 异常类结构图
注意:ClassNotFoundException不是RuntimeException;
是继承ReflectiveOperationException类,ReflectiveOperationException直接继承的Exception,所以ClassNotFoundException不是运行时异常。是可检查异常。
1.2.1 Throwable
Throwable 是 Java 语言中所有错误与异常的超类。
Throwable 包含两个子类:Error(错误)和 Exception(异常),它们通常用于指示发生了异常情况。
Throwable 包含了其线程创建时线程执行堆栈的快照,它提供了printStackTrace() 等接口用于获取堆栈跟踪数据等信息。
1.2.2 Error
定义:Error 类及其子类。程序中无法处理的错误,表示运行应用程序中出现了严重的错误。
特点:此类错误一般表示代码运行时 JVM 出现问题。
通常有:
VirtualMachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)、OutOfMemoryError:内存不足错误、StackOverflowError:栈溢出错误。
此类错误发生时,JVM 将终止线程。这些错误是不受检异常
,非代码性错误。因此,此类错误发生时跟应用程序无关,应用程序不用去处理此类错误。
1.2.3 Exception
程序本身可以捕获并且可以处理的异常。Exception 这种异常分为两类:运行时异常和编译时异常。
运行时异常
定义:RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。
特点:Java 编译器不会检查它。也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。比如NullPointerException空指针异常、
ArrayIndexOutBoundException数组下标越界异常、ClassCastException类型转换异常、ArithmeticExecption算术异常。此类异常属于不受检异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。虽然Java 编译器不会检查运行时异常,但是我们也可以通过 throws 进行声明抛出,也可以通过 try-catch 对它进行捕获处理。如果产生运行时异常,则需要通过修改代码来进行避免。例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生!
RuntimeException 异常会由 Java 虚拟机自动抛出并自动捕获(就算我们没写异常捕获语句运行时也会抛出错误!!),此类异常的出现绝大数情况是代码本身有问题应该从逻辑上去解决并改进代码。
编译时异常
定义: Exception 中除 RuntimeException 及其子类之外的异常。
特点: Java 编译器会检查它。如果程序中出现此类异常,比如
ClassNotFoundException(没有找到指定的类异常),IOException(IO流异常),要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。该异常我们必须手动在代码里添加捕获语句来处理该异常。
1.2.3 受检异常(checked exception)与非受检异常(unchecked exception)
Java 的所有异常又可以分为受检异常和非受检异常。
(与编译时异常和运行时异常感觉一模一样,都是根据编译器是否检查分类的)
受检异常:就是在编译的时候会检查到的异常,你必须用throw、try…catch等来处理这些异常,不然编译无法通过。
非受检异常:就是编译的时候检查不到的异常,即使你不处理这些异常,也可以编通过可以运行。但是运行过程中可能出现这些异常。
二、Java异常关键字
2.1 关键字
5个关键字:
- try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
- catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。
- finally – finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。
- throw – 用于方法内部抛出异常。
- throws – 用在方法后面,用于声明该方法可能抛出的异常。
注意:
- 即使try或者catch块中的有return或者throw语句,也只有等finally块执行完成之后,才会回来执行try或者catch块中的return或者throw语句;
- 如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
2.2 throw和throws的区别
- throw – 用于方法内部抛出异常。
- throws – 用在方法后面,用于声明该方法可能抛出的异常。
throw:
try{throw new Exception(); // 抛出一个异常}catch (Exception e){e.printStackTrace();}
throws:
// 方法A中throws声明可能抛出的异常public static void functionA() throws Exception{int[]a = {1,2,3};System.out.println(a[3]);}// main方法public static void main(String[] args) {try{functionA();}catch (Exception e){e.printStackTrace();}}
main方法
调用functionA()
方法,由调用者(main方法)捕获和处理异常
区别:
- 1.throw是在方法内部抛出异常;throws是方法后面使用,用于声明异常。
- 2.throw实际抛出了异常;throws只是声明,不一定实际抛出,只有方法中出现声明的异常才会抛出。
- 3.throw的异常处理,需要在方法体中catch;throws可以一直向上(方法调用者)传递,如果一直没有处理,最后由jvm默认的异常处理器来处理。
三、自定义异常&自定义全局异常处理器
3.1 自定义异常
步骤:
(1)继承 Exception 或 RuntimeException
(2)定义构造方法
(3)使用异常
代码示例:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor //生成有参数构造方法
@NoArgsConstructor //生成无参数构造
public class GuliException extends RuntimeException {private Integer code;//状态码private String msg;//异常信息
}
自定义异常的使用:
try {int i = 10/0;}catch(Exception e) {//执行自定义异常throw new GuliException(20001,"执行了自定义异常处理....");}
3.2 全局异常处理器(springboot版)
使用以下注解实现全局异常处理:
@ControllerAdvice :定义全局异常处理类
@ExceptionHandler:指定出现什么异常执行这个方法
@ResponseBody:为了返回数据
@ControllerAdvice
+@ResponseBody
=@RestControllerAdvice
每个方法都用到了@ResponseBody注解,可以把@ControllerAdvice + @ResponseBody合并成@RestControllerAdvice注解
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice
public class GlobalExceptionHandler {//指定出现什么异常执行这个方法@ExceptionHandler(Exception.class)@ResponseBody //为了返回数据public void error(Exception e) {e.printStackTrace();System.out.println("执行了全局异常处理..");}//特定异常@ExceptionHandler(ArithmeticException.class)@ResponseBody //为了返回数据public void error(ArithmeticException e) {e.printStackTrace();System.out.println("执行了ArithmeticException异常处理..");}//自定义异常@ExceptionHandler(GuliException.class)@ResponseBody //为了返回数据public R error(GuliException e) {e.printStackTrace();System.out.println(e.getMsg());}}
四、常见异常
java.lang包下的常见异常类:
1. NullPointerException(空指针异常)
空指针异常。
调用了未经初始化的对象或者是不存在的对象。经常出现在创建图片,调用数组这些操作中,比如图片未经初始化,或者图片创建时的路径错误等等。对数组操作中出现空指针,即把数组的初始化和数组元素的初始化混淆起来了。数组的初始化是对数组分配需要的空间,而初始化后的数组,其中的元素并没有实例化,依然是空的,所以还需要对每个元素都进行初始化(如果要调用的话)。
阿里巴巴Java开发手册中写道:防止NPE,是程序员的基本修养。
2. ClassNotFoundException
指定类不存在异常。
指定的类不存在这里主要考虑一下类的名称和路径是否正确即可,通常都是程序试图通过字符串来加载某个类时可能引发 异常
比如:调用Class.forName();或者调用ClassLoad的finaSystemClass();或者LoadClass();
3. NumberFormatException
字符串转换为数字异常。
当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常.如现在讲字符型的数据“123456”转换为数值型数据时,是允许的。但是如果字符型数据中包含了非数字型的字符,如123#56,此时转换为数值型时就会出现异常。系统就会捕捉到这个异常,并进行处理。
4. IndexOutOfBoundsException
数组下标越界异常。
查看调用的数组或者字符串的下标值是不是超出了数组的范围,一般来说,显示(即直接用常数当下标)调用不太容易出这样的错,但隐式(即用变量表示下标)调用就经常出错了,还有一种情况,是程序中定义的数组的长度是通过某些特定方法决定的,不是事先声明的,这个时候,最好先查看一下数组的length,以免出现这个异常。
5. IllegalArgumentException
方法的参数错误。
比如g.setColor(int red,int green,int blue)这个方法中的三个值,如果有超过255的也会出现这个异常,因此一旦发现这个异常,我们要做的,就是赶紧去检查一下方法调用中的参数传递是不是出现了错误。
6. IllegalAccessException
没有访问权限。
当应用程序要调用一个类,但当前的方法即没有对该类的访问权限便会出现这个异常。对程序中用了Package的情况下要注意这个异常
7. ArithmeticException
数学运算异常。
当算术运算中出现了除以零这样的运算就会出这样的异常。
8. ClassCastException
数据类型转换异常。
当试图将对某个对象强制执行向下转型,但该对象又不可转换又不可转换为其子类的实例时将引发该异常,如下列代码。
Object obj = new Integer(0);
String str = obj;
9. FileNotFoundException
文件未找到异常。
当程序试图打开一个不存在的文件进行读写时将会引发该异常。该异常由FileInputStream,FileOutputStream,RandomAccessFile的构造器声明抛出,即使被操作的文件存在。但是由于某些原因不可访问,比如打开一个只读文件进行写入,这些构造方法仍然会引发异常。
10. ArrayStoreException
数组存储异常。
当试图将类型不兼容类型的对象存入一个Object[]数组时将引发异常
Object[] obj = new String[3];
obj[0] = new Integer(0);
11. NoSuchMethodException
方法不存在异常。
当程序试图通过反射来创建对象,访问(修改或读取)某个方法,但是该方法不存在就会引发异常。
12. NoSuchFiledException
方法不存在异常。
当程序试图通过反射来创建对象,访问(修改或读取)某个filed,但是该filed不存在就会引发异常
13.EOFException
文件已结束异常。
当程序在输入的过程中遇到文件或流的结尾时,引发异常。因此该异常用于检查是否达到文件或流的结尾
14. InstantiationException
实例化异常。
当试图通过Class的newInstance()方法创建某个类的实例,但程序无法通过该构造器来创建该对象时引发;
Class对象表示一个抽象类,接口,数组类,基本类型
该Class表示的类没有对应的构造器
15:nterruptedException
被中止异常。
当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。
16:CloneNotSupportedException
不支持克隆异常。
当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常。
17:OutOfMemoryException
内存不足错误
当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
18:NoClassDefFoundException
未找到类定义错误
当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误。
其它异常:
违背安全原则异常:SecturityException
操作数据库异常:SQLException
输入输出异常:IOException
通信异常:SocketException
更多推荐
Java异常及处理
发布评论