概念
在程序运行过程中出现的例外情况,在Java中,异常是一种比较重要的消息机制。
异常类
异常的体系结构
Throwable是所有异常类的共同父类;Error是所有错误的父类;Exception是所有编译时异常类的父类;
Exception有两个分支,一个是运行时异常RuntimeException,如NullPointerException 、 ClassCastException;;另一个是检查异常,如 I/O 错误导致的 IOException、SQLException。
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
RuntimeException表示运行时异常,是那些可能在在 Java 虚拟机正常运行期间抛出的异常的超类。如果出现 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<String, User> userMap = new HashMap<String, User>(); 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://blog.csdn.net/hguisu/article/details/6155636
本文深入解析Java中的异常处理机制,包括异常的概念、异常类体系结构、异常处理机制、自定义异常类等内容,帮助读者理解并掌握Java异常处理的实践。


50

被折叠的 条评论
为什么被折叠?



