1. 异常机制
异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。
程序错误分为三种:
1.编译错误(checked异常);2.运行时错误(unchecked异常);3.逻辑错误。
(1)编译错误是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因和位置,这个也是大家在刚接触编程语言最常遇到的问题。
(2)运行时错误是因为程序在执行时,运行环境发现了不能执行的操作。
(3)逻辑错误是因为程序没有按照预期的逻辑顺序执行。异常也就是指程序运行时发生错误,而异常处理就是对这些错误进行处理和控制。
2. 异常结构
在 Java 中,所有的异常都有一个共同的祖先 Throwable(可抛出)。Throwable 指定代码中可用异常传播机制通过 Java 应用程序传输的任何问题的共性。
Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。异常和错误的区别是:异常能被程序本身可以处理,错误是无法处理。
Trowable类中常用方法如下:
-
返回异常发生时的详细信息
public string getMessage(); -
返回异常发生时的简要描述
public string toString(); -
返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同
public string getLocalizedMessage(); -
在控制台上打印Throwable对象封装的异常信息
public void printStackTrace();
3. 异常和错误的区别
Error(错误):
是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。
Exception(异常):
是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。
Exception(异常)分两大类:运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。
1.运行时异常(unchecked):都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
2.非运行时异常(checked) (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
通常,Java的异常(Throwable)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。
1. 可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。除了Exception中的RuntimeException及RuntimeException的子类以外,其他的Exception类及其子类(例如:IOException和ClassNotFoundException)都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
2. 不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。RuntimeException表示编译器不会检查程序是否对RuntimeException作了处理,在程序中不必捕获RuntimException类型的异常,也不必在方法体声明抛出RuntimeException类。RuntimeException发生的时候,表示程序中出现了编程错误,所以应该找出错误修改程序,而不是去捕获RuntimeException。
4. 异常的处理机制
- 抛出异常:
当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。 - 捕获异常:
在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
总体来说,Java规定:对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException和Error
常见的异常:
实际开发的经验总结
异常的处理机制:通常时抛出异常(unchecked),在某个地方统一处理,
优点有以下几个方面:
• Unchecked异常不会使代码显得杂乱,因为其避免了不必要的try-catch块。
• Unchecked异常不会因为异常声明聚集使方法声明显得杂乱。
• Unchecked异常避免了版本问题。
5. 异常的使用
5.1 在异常使用之前,我们需要明白两个问题
- 为什么要创建自己的异常?
答:当Java内置的异常都不能明确的说明异常情况的时候,需要创建自己的异常。 - 应该在声明方法抛出异常还是在方法中捕获异常?
答:捕捉并处理知道如何处理的异常,而抛出不知道如何处理的异常。
5.2 异常的具体使用 - 如何自定义异常
public class CustomException extends Exception {
//无参构造方法
public CustomException(){
super();
}
//有参的构造方法
public CustomException(String message){
super(message);}
// 用指定的详细信息和原因构造一个新的异常
public CustomException(String message, Throwable cause){
super(message,cause);
}
//用指定原因构造一个新的异常
public CustomException(Throwable cause) {
super(cause);
}
//返回此 throwable 的详细消息字符串。
public String getMessage(){}
}
在开发中,我们一般重写标记红色的方法即可。
实际开发中通常自定义运行时异常(unchecked)
public class CustomException extends RuntimeException{----}
(2)自定义异常的应用原则:
自定义异常的规则
在Java中可以自定义异常,编写自己的异常类时需要记住以下几点:
1.所有异常都必须是Throwable的子类。
2.如果写一个检查异常类(checked),则需要继承Exception类。
3.如果写一个运行时异常类(unchecked),则需要继承RuntimeException类。
一般在开发中,推荐使用 继承RuntimeException,自定义异常