什么是异常
异常:程序在运行过程中产生的不正常情况。
程序在运行的时候,发生了一些不被预期的事件,从而没有按照我们编写的代码执行,这就是异常。
异常是Java
中的错误,但是并不是所有的错误都是异常,比如说,你在定义变量名的时候没有依照Java
的规则,在语句的结尾少了一个分号,那么运行出来结果是提示是错误 java.lang.Error
;
不过如果你用System.out.println(5/0)
,那这个时候你的程序是可以正常编译的,但是在运行的时候,因为你用0
做了除数,会抛出 java.lang.ArithmeticException
的异常。
异常的原因有很多种,比如:
- 输入了错误的数据,比如:程序需要的是
int
类型数据,而用户输入了一串字符串。 - 对象没有初始化就调用:下面这段代码就会提示空指针异常。
要理解Java
中的异常是如何工作的,你需要掌握以下三种类型的异常:
1 检查性异常
例如我们要打开一个文件时,这段代码就可能存在异常,因为这个文件很有可能并不存
File f = new File("G://test.java"); FileInputStream fs = new FileInputStream(f);
这里G
盘下的test.java
文件就可能不存在,这个时候运行这段代码就可能会出异常,所以在我们编写代码的时候IDE会提示我们要处理这段代码可能出现的异常。
如果我们不处理的话,程序是不能被编译的。
2 运行时异常
运行时异常程序员可以不去处理,当异常出现时,虚拟机会处理。常见的运行时异常有空指针异常。
常见的运行时异常:
ClassCastException(类转换异常)
IndexOutOfBoundsException(数组越界)
NullPointerException(空指针)
ArrayStoreException(数据存储异常,操作数组时类型不一致)
3 错误
错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
Exception 类
所有的异常类都是从 java.lang.Exception
类继承的子类。
Exception
类是 Throwable
类的子类。除了Exception
类之外,Throwable
还有一个子类Error
。
Java
程序通常不捕获错误。错误一般发生在严重故障时,它们在Java
程序处理的范畴之外。
Error
用来指示运行时环境发生的错误。
例如,JVM
内存溢出。一般地,程序不会从错误中恢复。
异常类有两个主要的子类:IOException
类和 RuntimeException
类。
捕获异常
Java中提供了一个捕获异常的机制:try-catch-finally
try{ 可能出现的异常代码 }catch(ExceptionType1 e1){ 对该异常的处理方式 }catch(ExceptionType2 e2){ 对该异常的处理方式 }catch(Exception......){ 对该异常的处理方式 }finally{ 无论是否异常都会执行 }
通过这两个单词的字面意思我们就能很好的理解了:try
:尝试,catch
:捕获。
尝试执行try 中代码如果这try代码有出现了异常,就会执行catch
中的语句,try没有异常就不会执行catch
代码,继续正常执行下面代码
。
try不能单独使用,要与catch或finally结合。一个try可以对应多个catch和一个finally。当有多个catch时,每次异常只能执行一个catch,若处理的多个异常之间存在异常关系,则因先处理子类异常,即将子类异常放在前面。例:
try{ System.out.println(10 / 0); }catch(ArithmeticException e){ System.out.println("ArithmeticException e"); }catch(Exception e){ System.out.println("Exception e"); }
输出结果:
ArithmeticException e
若try中同时有多段代码,当某处出现异常后,其在try中剩余的代码不会再执行,而是直接执行catch中的代码。
非检测型异常:
异常 | 描述 |
ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数”除以零”时,抛出此类的一个实例。 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
检测性异常:
异常 | 描述 |
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
IOException及其子类 | 对文件或流的操作有误时,抛出异常 |
throw与throws
throw关键字的作用是:主动抛出异常;throw
是语句抛出一个异常,一般是在代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常。
throw的声明方法:
1 throw new ExceptionType("异常的描述"); 2 ExceptionType e = new ExceptionType("异常的描述”); throw e;
throws出现在方法名中:
修饰符 返回类型 方法名 (参数列表)throws ExceptionType{ 方法体 }
throws的使用场景:主动抛出的异常没有解决时,用throws向上抛出异常。如果在函数体内使用throw抛出了某种异常,最好要在函数名中加throws抛异常声明,然后交给调用它的上层函数进行处理。
例 :需要throws 因为没有处理
public static void main(String[] args) throws Exception{ int a = 0; int b = 10; if (a == 0)throw new Exception("余数为0"); }
不需要throws 因为通过try-catch处理了 其中catch捕获的异常就是throw抛出的异常 自定义异常
public static void main(String[] args){ int a = 0; int b = 10; try { if (a == 0)throw new Exception("余数为0"); }catch (Exception e){ System.out.println(e.toString()); } }
1 throws出现在方法函数头;而throw出现在函数体。
2 throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。
3 两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理
自定义异常
继承Exception
class 自定义异常名 extends Exception{ //因为Exception已经实现了很多异常处理的方法了属性了, //所以自定义异常只需要将信息传递给父类(使用super关键字)即可 }
要用throw 自定义异常名 抛出。