Java中有一个异常处理机制。在我们运行的程序中,出现异常却不去处理的话,整个程序就会终止运行。在面向用户编写程序时更要注意,毕竟墨菲也说了,“ 如果坏事情有可能发生,不管这种可能性多么小,它总会发生,并引起最大可能的损失。”所以我们要在编写程序时就应该及时处理这些引起的异常。
下面是一个大概的流程,主要分为,异常体系和异常处理(补救)。
一、异常体系
Throwable
Throwable 是Java中所有错误或异常的超类,只有一个类(或其子类)实例化了 Throwable 类,这个类才能叫做一个 错误 或 异常 ,才能被 Java 虚拟机、Java 语句 throw 抛出、被 try 接收,被 catch 捕获。
Throwable 有两个子类,分别是 Error (错误)和 Exception(异常),其中 Exception 可以将他的子类分为两个部分, RuntimeException(运行时错误) 和其他子类。为什么这样分呢?是因为,在Java的异常体制中,将错误及异常分为两个大类,分别是,非检查异常和检查异常。
非检查异常: Error 全部子类、RuntimeException
检查异常:Exception 中除 RuntimeException 外的所有子类。
两者有什么区别?
非检查异常: 通常在编码时,不对非检查异常的处理提出明确的要求。
非检查异常有 Error 和 RuntimeException 。Error 指 JVM (Java虚拟机)的错误,较常见的是栈溢出、内存不足的错误,像StackOverflowError、OutOfMemoryError 等都是JVM 中的错误。RuntimeException 是运行时错误,例如,NullPointerException(空指针)、IndexOutOfBoundsException(数组越界) 等,是你编码时无法直接发现,而是在编译或运行时发现的异常。
怎么处理?(捕获、抛出、代码修改、不处理)对于非检查异常,你可以直接在代码中进行处理,例如利用 throw 抛出、利用 try catch 直接进行处理,但是由于这种错误非常多而且难以控制,如果你打算通过上述方法直接进行处理的话,代码量将会非常的巨大、可读性将会非常差。因此,一般建议在编码时考虑周全、严谨。亦或者,你还可以完全不管。
例如,在处理数组越界 IndexOutOfBoundsException 异常时,你自然可以通过 try catch 来捕获、处理异常。但是其实你只需要在进行相关数组操作前,判断 index 是否在数组范围内即可。如下:
ArrayList<Point> list = new ArrayList<Point>();
int index = 5;
// 直接利用 try catch 捕获、处理
try {
list.get(index);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
// 判断
if (index >= 0 && index < list.size())
list.get(index);
检查异常: 在编码的时候,编译器要求你必须要处理的问题。即你在编码的过程中,编译器就会给出相应的错误信息提示。要求你一定要 解决,否则无法编译通过。
检查异常是 Exception 类的子类中除 RuntimeException 外的全部子类。例如线程休眠语句 sleep(100); 在你敲好这句代码后,编译器就会提示你一个异常 : InterruptedException .
怎么处理。(抛出、捕获)。你自然可以直接抛出,但是在程序中,抛出的错误始终也是需要解决的,并且,错误一般有其发生错误特定的环境,向外 throw 抛出越多,就越难以根据具体环境进行相关捕获后的处理操作。所以一般建议,直接进行捕获、处理(某些情况下还是需要抛出的)。
二、自定义异常类
当Java提供的异常类不能满足特定环境下的异常检查时,个人根据具体情况,编写的一个继承 Exception 类的类。
例如,在银行的存钱系统中,如果你的入账资金是一个负数,那这就是一个错误,但是Java提供的错误、异常类并不会检测出来,因此在这种情况下,你需要自己写一个异常,如下:
自定义一个 异常类
public class BankException extends Exception {
String message;
public BankException(int m) {
message = "存入的款项为" + m + ",是一个负数,输入错误。";
}
public void printMessage() { //打印异常信息
System.out.println(message);
}
}
在某一个类中使用,注意,在要抛出异常的方法声明时,用 throws 声明产生的异常
![](https://i-blog.csdnimg.cn/blog_migrate/c63ca74a17eef3f95870770421a972da.png)
在另外一个操作类中调用 Bank 中的inputMoney 方法的时候一定要进行相应的异常处理,你可以选择抛出或用 try catch 捕获。否则就会报错
public class Operator {
public static void main(String[] args) {
Operator operator = new Operator();
operator.addMoney();
}
int money = 0;
public void addMoney() {
Bank bank = new Bank(money);
System.out.println("第一笔钱 50元");
try {
money = bank.inputMoney(50);
} catch (BankException e) {
e.printStackTrace();
}
System.out.println("第一笔钱操作结束");
System.out.println("第二笔钱 -50元");
try {
money = bank.inputMoney(-50);
} catch (BankException e) {
e.printMessage(); //这是我们在自定义异常编写的输出语句
e.printStackTrace(); //这是Throwable 类定义的异常输出语句
}
System.out.println("第二笔钱操作结束");
System.out.println("余额为"+money);
}
}
输出结果为:
在Java的检查异常类中,类的构建基本都是这样,例如 Thread 类中的 sleep() 方法,源代码如下:
public static void sleep(long millis, int nanos) throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
三、异常处理
1. 对于非检查异常,你最好使得代码更加得严谨,结合Java给出的错误、异常信息,通过打印数据,一步步检查,或者通过断言一步步跟踪。当然,你也可以使用处理异常的关键字,但是这有时会使得代码较长。
2. 对于检查异常,通过关键字的捕获、处理来解决。有五个关键字,try、 catch 、finall 、throw、throws
try catch 配套使用,catch 的作用就是捕获 throw 关键字抛出的异常对象。
(当可能产生的异常种类很多的时候,建议最后catch中的参数类型为 Exception ,避免漏掉某些异常没有捕获)
try{
//会引起异常的代码
}catch( 某检查异常类 e){
//捕获异常后进行的相关操作
}catch(Exception e){ //这里的参数类型,可以是检查异常共有的父类,也可以是单独不同的具体异常类
//捕获异常后进行的相关操作
}
finally 最后输出的语句,即使在 try 和 catch 有 return ,也会在执行完 finally 语句后才去执行 return 语句, finally 语句中不可以有return 语句,try 和 catch 中可以有,但是不建议将return语句放在 try 和 catch 中。
try{
//有可能发生异常的代码
} catch(异常类 变量)
{
// 处理异常的代码,捕获
}
finally{
//一定会被执行的代码
}
public static void main(String[] args) {
Test test = new Test();
int m =test.init();
System.out.println("m = "+m);
}
public int init() {
int m = 0;
try {
System.out.println("这里是try");
m = 5 / 0; // 这里会有一个非检查异常,catch 将其捕获
return m;
} catch (Exception e) {
System.out.println("这里是catch");
e.printStackTrace(); //打印错误信息
return -1;
} finally {
System.out.println("这里时finally语句");
}
}
输出为:
throw 和 throws 的使用参照自定义异常类部分。