1. 什么是异常
异常就是程序执行过程中,因为某些原因导致程序不能正常执行,这些原因可能是:进行运算时除数为零,网络通信时连接中断,或JVM内存溢出等等。这些异常可能是因为用户引起的例如程序打算接收用户输入的数字,结果用户缺输入了其他字符,有的是程序错误引起的比如忘记写分号…
想要深刻理解java的异常处理机制,首先要理解以下三种类型的异常:
- 运行时异常 :运行时异常是程序员可以解决的,可以在编译器被忽略,例如程序访问了没有初始化的对象的某个属性就会报出:java.util.NullPointException(空指针异常)
- 检查性异常 :检查性异常是程序员无法解决的,这些异常不能再编译时被忽略,例如程序期望收到一个数字类型的数据,而用户输入了一个非数字类型字符,这样就会导致:java.util.InputMismatchException(输入不匹配异常)
- 错误 : 错误不是异常。错误在代码中通常被忽略。例如,无线递归导致栈溢出时,一个错误就发生了,它们在编译也检查不到的。
2. Exception类的继承结构
所有的异常类是从 java.lang.Exception 类继承的子类。Exception 类是 Throwable 类的子类。除了Exception类外,Throwable 还有一个子类 Error 。Exception类有两个子类:IOException,RuntimeException。
3. 常见的异常类型
异常 | 描述 |
---|---|
ClassNotFoundException | 应用程序找不到相应的类,抛出该异常 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
… | … |
4. Throwable方法
方法 | 描述 |
---|---|
getMessage() | 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 |
getCause() | 返回一个 Throwable 对象代表异常原因。 |
toString() | 返回此 Throwable 的简短描述。 |
printStackTrace() | 将此 Throwable 及其回溯打印到标准错误流。 |
getStackTrace() | 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 |
fillInStackTrace() | 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 |
5. 捕获异常(try catch finally)
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。
public class App
{
public static void main( String[] args ) {
File file = new File("config.yml");
try {
FileInputStream fileInputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} finally {
System.out.println("file文件不存在");
}
}
}
上面的代码捕获了FileNotFoundException异常try代码块中写入可能发生异常的语句,当程序捕获到异常将会停止执行异常语句之后的代码,从而执行finally代码块的方法。
也可以通过多个catch代码块来捕获多个异常。
try{
// 程序代码
}catch(异常类型1 变量){
// 程序
}catch(异常类型2 变量){
// 程序
}catch(异常类型3 变量){
// 代码
}
程序会根据系统捕获到的不同异常类型从而执行相应的方法。
6. throws/throw 关键字:
通过使用throws 和throw关键字可以抛出一个异常,交给上层代码处理。
如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
public class App
{
public static void main( String[] args ) throws FileNotFoundException {
File file = new File("config.yml");
FileInputStream fileInputStream = new FileInputStream(file);
}
}
上面的代码将FileNotFoundException异常抛出。
如果程序设计者调用了一个会抛出异常的方法,要么处理这个异常,要么将异常继续抛出。
由方法抛出的异常交给系统处理(需要同学明确Java对异常强制检查要求的知识)
- Java 对 Exception 类中的异常可分为检查型异常和非检查型异常两类。
- 非检查型异常都是RuntimeException类的子类,Java编译器对非检查型异常不要求进行捕获和处理也能通过编译;而不是RuntimeException类子类的异常则都是受检查型异常,例如方法抛出这类异常,调用者必须处理该异常。
- 对于受检查型异常,如果调用者不处理,则必须在最后的 main 方法中将异常提交给系统。(上诉代码)
7. 自定义异常类型
通过继承 Exception类 可以自定义一个异常类型,从而提高程序安全性,自定义异常需要满足下列条件:
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
我们通过乔布斯买苹果手机来全面理解自定义异常
乔布斯手里拿了5000元想去苹果商店买一部iphone13但是,iphone13需要5399元,这样一来,乔布斯进入商店购买商品后就会引发异常。
消费者代码:
//消费者
class consumer{
private String name;
private int money;
public consumer(String name, int money) {
this.name = name;
this.money = money;
}
public String getName() {
return name;
}
public int getMoney() {
return money;
}
}
iphone13商店代码:
// 苹果手机
class iphone13{
private int price; // 价格
private int inventory; // 库存
public iphone13(int price, int inventory) {
this.price = price;
this.inventory = inventory;
}
/**
* 出售iphone13
* @param shopingNum 购买数量
* @param consumer 消费者信息
* @return 购买状态
* @throws InsufficientBalanceException 如果消费者没钱 抛出异常
*/
public boolean sell(int shopingNum, consumer consumer) throws InsufficientBalanceException {
if (this.inventory > 0 ){
if (shopingNum * this.price < consumer.getMoney()){
this.inventory -= shopingNum ;
System.out.println("成功出售iphone" + this.price + "台, 商店库存:" + this.inventory);
}else {
// 在库存充足的情况下如果顾客余额不足以购买商品抛出异常... <-- 重要代码
throw new InsufficientBalanceException("顾客" + consumer.getName() + "余额不足,赶出商店...");
}
}
System.out.println("出售失败,库存不足");
return false;
}
}
自定义异常代码:
// 当消费者余额不足是触发异常
class InsufficientBalanceException extends Exception{
public InsufficientBalanceException(String message) {
super(message);
}
}
Main代码:
public class App {
public static void main( String[] args ) {
consumer Jobs = new consumer("乔布斯", 5000);
iphone13 iphone13 = new iphone13(5399,20);
//乔布斯想要买一个苹果手机
System.out.println("乔布斯执意要买一个苹果手机,但是他只有5000元...");
System.out.println("开始购买...");
try { // 可能会发生异常的位置,将异常捕获 <-- 重要代码
iphone13.sell(1,Jobs);
} catch (InsufficientBalanceException e) {
throw new RuntimeException(e);
} finally {
System.out.println("经过激烈的争吵后," + Jobs.getName() + "骂骂咧咧的离开了...");
}
}
}
C:\Users\Administrator\.jdks\jdk\bin\java.exe ...
乔布斯执意要买一个苹果手机,但是他只有5000元...
开始购买...
经过激烈的争吵后,乔布斯骂骂咧咧的离开了...
Exception in thread "main" java.lang.RuntimeException: org.example.InsufficientBalanceException: 顾客乔布斯余额不足,赶出商店...
at org.example.App.main(App.java:73)
Caused by: org.example.InsufficientBalanceException: 顾客乔布斯余额不足,赶出商店...
at org.example.iphone13.sell(App.java:52)
at org.example.App.main(App.java:70)
进程已结束,退出代码1
以上就是java异常处理机制的基本理解,如有问题,欢迎指正。