在程序运行过程中出现的例外情况,在Java中,异常是一种比较重要的消息机制。
异常的体系结构
Throwable是所有异常类的共同父类;Exception是所有编译时异常类的父类;RuntimeException是所有运行时异常类的父类。
Throwable
所有异常类都是直接或者间接继承Throwable,Throwable类源码如下:
public class Throwable implements Serializable { //...... }
其主要方法如下:
public String getMessage() 返回关于发送的异常的详细消息。这个消息在Throwable 类的构造函数中初始化了。 public Throwable getCause() 返回一个Throwable对象代表异常原因。 public String toString() 使用getMessage()的结果返回类的串级名字。 public void printStackTrace() 打印toString()结果和栈层次到System.err,即错误输出流。 public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 public Throwable fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 Error
Error表示错误,对于所有的编译时期的错误以及系统错误都是通过Error抛出的。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。在 Java中,错误通过Error的子类描述。
Exception
Exception表示异常,与Error的区别在于:异常能被程序本身可以处理,错误是无法处理。
Exception的源码如下所示:
public class Exception extends Throwable { static final long serialVersionUID = -3387516993124229948L; public Exception() { super(); } public Exception(String message) { super(message); } public Exception(String message, Throwable cause) { super(message, cause); } public Exception(Throwable cause) { super(cause); } protected Exception(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
RuntimeException
源码如下:
public class RuntimeException extends Exception { static final long serialVersionUID = -7034897190745766939L; public RuntimeException() { super(); } public RuntimeException(String message) { super(message); } public RuntimeException(String message, Throwable cause) { super(message, cause); } public RuntimeException(Throwable cause) { super(cause); } protected RuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
在Java中,异常处理机制为:捕获异常和抛出异常。
try-catch语句块用于捕获和处理程序代码抛出的异常
try{ //可能出现异常的代码,当某个代码语句块出现异常后,其后面的代码语句块不会执行。 }catch (异常类型名 引用名){ //异常处理的代码 }
当代码块出现异常后,会执行throw new 异常类型名();然后catch语句会捕捉:异常类型名 引用名 = new 异常类型名();
多重捕获块
catch语句块可以出现多次
try{ //可能出现异常的代码,当某个代码语句块出现异常后,其后面的代码语句块不会执行。 }catch (异常类型名 引用名){ //异常处理的代码 }catch (异常类型名 引用名){ //异常处理的代码 }......
finally关键字
正常情况下, 无论程序是否发生异常,finally语句都会执行。因此,在finally语句块里面放置释放资源的语句(例如:关闭数据库连接对象)。
- 注意事项
1.调用System.exit(0);使JVM停止,finally语句因此不会执行。 2.调用return则不会影响finally语句执行。如下:会输出finally
try{
return;
}finally{
System.out.println("finally");
}
- 使用
try{ //可能出现异常的代码,当某个代码语句块出现异常后,其后面的代码语句块不会执行。 }catch (异常类型名 引用名){ //异常处理的代码 }finally{ // }
总结
try语句块必须要出现,catch和finally两者必须出现其一或者同时出现,否则报错。能够处理的异常尽量处理,处理不了的异常再抛出去。
throw关键字
throw用于抛出一个异常。如下所示:
public void deposit(double amount) throws RemoteException{ //...... throw new RemoteException(); }
throws关键字
从方法中抛出的任何异常都必须使用throws。一个方法可以声明抛出多个异常,多个异常之间使用逗号分隔开。如下所示:
public void withdraw(double amount) throws RemoteException, IOException{ //...... }
Exception 这种异常分两大类运行时异常和编译时异常(非运行时异常)。
1.编译时异常(非运行时异常)
Exception类和Exception的子类且除了RuntimeException类及其子类的异常都是编译时异常。
编译时异常要求程序在编译期间必须要对其进行处理,若不处理则要声明抛出的异常类型(在方法上使用throws关键字声明异常类型)。
2.运行时异常
RuntimeException类和RuntimeException的子类都是都是运行时异常。
运行时异常在程序编译期间可以处理也可以不处理。如果不处理则不用通过throws关键字声明抛出的异常类型。
3.编译时异常和运行时异常的区分
编译时不是程序的Bug,而是为了让程序健壮和稳定;运行时异常是程序的Bug。 4.常见异常
ArithmeticException 当出现异常的运算条件时抛出此异常。如被除数为0 ArrayIndexOutOfBoundsException 用非法索引访问数组时抛出的异常(索引为负数或者大于等于数组的大小时)。 ClassCastException 当试图将对象强制转换为不是实例的子类时,抛出该异常(类型转换异常)。 IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。 IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 NullPointerException 当应用程序试图在需要对象的地方使用 null
时,抛出该异常。NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 StringIndexOutOfBoundsException 此异常由 String
方法抛出,指示索引或者为负,或者超出字符串的大小。ClassNotFoundException 应用程序试图加载类时,找不到相应的类,抛出该异常。 CloneNotSupportedException 当调用 Object
类中的clone
方法克隆对象,但该对象的类无法实现Cloneable
接口时,抛出该异常。IOException 操作输入流和输出流时可能出现的异常。 FileNotFoundException 文件未找到异常 NoSuchFieldException 字段未找到异常 NoSuchMethodException 方法未找到抛出的异常 NumberFormatException 字符串转换为数字抛出的异常
自定义编译时异常
编写一个类继承Exception或Exception的子类(除了RuntimeException及其子类),通常直接继承Exception即可。
自定义运行时异常
编写一个类继承RuntimeException或RuntimeException的子类,通常直接继承RuntimeException。
示例
下面以一个用户登录案例演示自定义运行时异常。
用户名不存在异常类:
/** * 自定义用户账户不存在运行时异常 * @author luckyliuqs */ public class UserNotExistException extends RuntimeException { private static final long serialVersionUID = 1L; public UserNotExistException() {} public UserNotExistException(String message) { super(message); } }
用户名或密码错误异常类:
/** * 自定义用户名或密码错误运行时异常 * @author luckyliuqs */ public class UserNameOrPasswordErrorException extends RuntimeException { private static final long serialVersionUID = 2L; public UserNameOrPasswordErrorException() {} public UserNameOrPasswordErrorException(String message) { super(message); } }
测试类:
public class UserLoginDemo { private static Map
userMap = new HashMap (); public static void main(String[] args) { userMap.put("Jack", new User("Jack", "12346")); try { User user = login("Jacks", "123456"); System.out.println("登录成功!"); } catch (UserNotExistException e) { //捕获异常 System.out.println("登录失败,原因:" + e.getMessage()); } catch (UserNameOrPasswordErrorException e) { //捕获异常 System.out.println("登录失败,原因:" + e.getMessage()); } } public static User login(String username, String password) { User user = userMap.get(username); if (user == null) { throw new UserNotExistException("用户不存在"); //抛出异常 } if (!password.equals(user.getPassword())) { throw new UserNameOrPasswordErrorException("用户名或密码错误"); //抛出异常 } return user; } }
参考:
https://www.runoob.com
https://blog.csdn.net/hguisu/article/details/6155636