一、什么是异常?
异常:就是不正常 程序在运行的过程,出现了一些突发状况,造成程序无法继续运行。我们把上述的突发状况,无法正常运行的这些状态称为Java中的异常。 Java中的异常:就是程序中出现的错误(bug),或者不正常现象
异常的产生过程解析
1)定义一个类ExceptionDemo;
2)定义一个主方法,在主方法中定义一个int类型的数组,在这个数组中存放int类型的数据;
3)在这个类中自定义一个函数getValue,在这个函数中根据调用者传递过来的下标和数组返回给调用者
对应的数据;
4)在主方法中调用自定义函数getValue,接收自定义函数返回回来的数据,并将数据打印到屏幕上;
说明:上述代码发生异常的过程是如何调试的
1)jvm先去调用main函数,在main函数中调用了getValue函数,然后jvm将getValue函数加载到内存中;
2)Jvm在执行getValue函数的时候,由于数组下标index的值3超过了数组的最大下标的范围,所以在这里发生了异常问题,ArrayIndexOutOfBoundsException(数组越界),这样导致程序就不会向下执行,jvm会在发生异常的地方停止,jvm会将发生异常信息(发生异常的位置、异常内容、异常类型等)封装到一个类中(Java的异常类),然后把这个封装了异常信息类的对象(new 异常类)丢给了当前调用函数的地方。
3)如果发生异常,jvm会自动创建封装了异常信息的异常类的对象,然后将对象使用throw关键字抛给调用getValue函数的地方。
4)由于getValue函数把问题抛给了main函数,所以导致了main函数中也有了异常,而main函数中的异常是被迫接收的,此时main函数中并没有解决此异常的解决方案,但是main函数是jvm调用的,所以main函数又将异常抛给了jvm虚拟机,jvm已经是底层了,不能再将异常抛出,jvm需要对这个问题进行处理,即将这个问题显示到屏幕上,让程序的使用者看到。
/*
针对发生的异常进行简单的处理
*/
class ExceptionDemo1
{
public static void main(String[] args)
{
//定义数组
int[] arr={1,2,5};
//int value=getValue(arr,1);
int value=getValue(arr,1);
System.out.println(value);
}
//定义函数根据指定的下标返回对应的值
public static int getValue(int[] arr,int index)
{
/*
以后在开发中,定义函数的时候,对外界传递过来的参数一定要
合法性的判断
这里需要对错误数据进行判断,然后将错误信息报告给调用者
在实际开发中我们一般会给固定的文件写错误信息(错误文档)
*/
//System.out.println("haha");
/*
* 发生空指针异常的地方,一定是使用了某个引用变量,而这个引用变量又不指向任何的对象
* 也就是说引用变量中保存的是null。这是使用空的引用调用属性或行为,而由于根本引用不指向
* 任何的对象,那么就没有属性和行为而言,更无法去调用了。肯定就发生空指针异常。
*/
if(arr==null)
{
throw new NullPointerException("对不起,数组引用变量的值不能为null");
}
if(index<0 || index>=arr.length)
{
throw new ArrayIndexOutOfBoundsException("下标越界了。。。");
}
return arr[index];
}
}
异常的体系
Throwable体系:
- Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。 在程序运行时,会产生一些错误信息。java把这些错误信息使用Error或其子类进行描述。 错误属于系统级别的,是由于JVM在操作内存时(JVM需要借助操作系统来实现内存的操作),出现了一些不正常的操作,造成内存错误,出现错误后操作系统就会把这个错误返回给JVM。在程序中,遇到错误时,java没有针对性的解决方案,只能通过修改源代码的方式来解决程序中的错误问题。
- Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。好比感冒。在程序运行时,也会出现一些异常状况。表示Java程序中存在的异常问题,而不是错误问题。这些异常问题,在程序中通过判断等形式是可以检测并且预防的。针对这些异常问题,程序员在写代码的时候一旦发生,必须给出有效的解决方案。java对于异常状况是有针对性的解决方案(异常处理),例:角标越界、空指针异常等。异常状况的发生,通常是JVM在操作一些数据时,出现的问题,java对于异常的发生,是可以通过一些手段(捕获)避免程序终止运行,保证让程序继续向下正常执行。
异常分类
- 编译时期异常:checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常)
- 运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会让编译器检测(不报错)。
二、异常问题怎么去解决和处理:
Java异常处理的五个关键字:try、catch、finally、throw、throws
抛出异常throw
throw new 异常类名(参数);
throw new NullPointerException("要访问的arr数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
声明异常throws
声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…
{
方法体
}
捕获异常try…catch
在开发中,main函数中不会出现声明,在main函数通常是使用捕获。
try{
编写可能会出现异常的代码
}catch(异常类型 对象名){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
try:该代码块中编写可能产生异常的代码。 catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。
获取异常信息
方法 | 说明 |
---|---|
getMessage() | 获取报错原因.获取异常的描述信息,原因(提示给用户的时候,就提示错误原因)。 |
toString() | 获取报错的类型和原因 |
printStackTrace() | 直接打印报错的类型、原因和位置.包含了异常的类型,异常的原因,还包括异常出现的位置. |
捕获多个异常
多个异常一次捕获,多次处理。
try{
编写可能会出现异常的代码
}catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
三、finally 代码块
finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
try…catch….finally:自身需要处理异常,最终还得关闭资源。
try{
可能发生异常的代码
}catch(异常类名 变量名){
处理异常的代码。
}finally{
程序中永远都能执行到的代码
}
四、自定义异常
什么是自定义异常类?
异常类如何定义?
- 自定义一个编译期异常: 自定义类 并继承于java.lang.Exception。
- 自定义一个运行时期的异常类:自定义类 并继承于java.lang.RuntimeException。
public class 异常类的名字 extends Exception / RuntimeException
{
//不需要任何的属性和行为,仅仅只需要提供构造函数即可。
public 异常类的名字(){}
public 异常类的名字( String message ){
super(message);
}
}
查看异常源码
public class NullPointerException extends RuntimeException {
//版本号 没什么用
private static final long serialVersionUID = 5162710183389028792L;
//构造方法
public NullPointerException() {
super();
}
//构造方法
public NullPointerException(String s) {
super(s);
}
}