1.异常
1.1异常概念
- 异常,指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常终止
- 在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象,Java处理异常的方式是中断处理
1.2异常体系
异常机制其实帮助我们找到程序中的问题,异常的根类是java.lang.Throwable,其中有两个子类,Error和Exception
Throwable体系:
- Error :严重的错误,无法通过的错误,只能事先避免,好比绝症
- Exception:表示异常,异常产生后可以通过代码的方式纠正
Throwable中的常用方法:
- public void printStackTrace( ):打印异常的详细信息
- public String getMessage( ):获取发生异常的原因
- public String toString( ):获取异常的类型和异常描述信息
1.3异常分类
- 顶层类 Throwable 派生出两个重要的子类, Error 和 Exception
- 其中 Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现,除了告知用户并使程序终止之外, 再无能无力. 这种情况很少出现.
- Exception 是我们程序员所使用的异常类的父类.
- 其中 Exception 有一个子类称为 RuntimeException , 这里面又派生出很多我们常见的异常类
NullPointerException , IndexOutOfBoundsException 等.
1.4异常的产生过程解析
2.异常的处理
Java处理异常的5个关键字:try catch finally throw throws
2.1抛出异常throw
2.1.1作用:
- 可以在指定的方法中抛出指定的异常
2.1.2格式:
- throw new xxxException(“异常的原因”)
2.1.3注意:
1.throw 关键字必须写在方法的内部
2.throw关键字后面的异常对象必须是Exception或者Exception的子类
3.throw关键字抛出的对象,我们必须要处理(1)throw后面的是RunTimeException或者是
RunTimeException的子类,我们可以不处理,默认交给JVM来处理
(2)throw后面的是编译期异常(写代码的时候报错),我们必须处理这个异常,要么 try……catch,要么throws
2.1.4代码示例:
public static void main(String[] args) {
int [] array = new int [3];
int e = getElement(array,3);
System.out.println(e);
}
public static int getElement(int [] array,int index){
if(array == null){
throw new NullPointerException("传递数组的值是null");
}
if(index < 0 || index >= array.length){
throw new ArrayIndexOutOfBoundsException("数组索引越界");
}
return array[index];
}
运行结果:
2.2声明异常throws
2.2.1作用:
- 当方法内部抛出异常对象的时候,那么我们必须处理这个异常对象,会把异常对象抛出给方法的调用者处理,最终交给JVM处理
2.2.2使用格式:
修饰符 返回值类型 方法名 (参数列表)throws XXXException{
throw new XXXException(“产生原因”);
}
2.2.3注意事项:
- throws关键字必须写在方法声明处
- throws关键字后面的异常必须是Exception或者Exception的子类
- 方法内部如果出现了多个异常对象,那么throws也要抛出多个对象,如果抛出的这个异常对象具有子父类关系,那么直接声明父类异常即可
- 调用了声明抛出异常的方法,我们就必须处理声明的异常。要么继续使用throws声明抛出,直到抛给JVM;要么使用try……catch来处理这个异常
2.2.4代码示例:
public static void main(String[] args) throws FileNotFoundException {
readFile("d:\\a.txt");
}
public static void readFile(String fileName) throws FileNotFoundException {
if(!fileName.equals("c:\\a.txt")){
throw new FileNotFoundException("文件的路径不是c:\\a.txt");
}
System.out.println("路径没有问题,读取文件");
}
运行结果:
2.3try……catch
2.3.1作用:
- try中存放可能出现异常的代码,catch中存放异常的处理逻辑
2.3.2使用格式:
try{
可能出现异常的代码;
catch( 定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑
}
2.3.3注意事项:
- try中可能有多个异常对象,那么可以使用多个catch来处理这些对象
- 如果try中没有产生异常,那么就不会执行catch中的捕获逻辑,但会继续执行try……catch之后的代码
- 一旦try中出现异常,那么try代码块中的程序就不会继续执行,而是交给catch中的代码执行,catch执行完毕继续往下执行
2.3.4代码示例:
public static void main(String[] args) {
try{
readFile("d:\\a.tx");
}catch (IOException e){
System.out.println("文件后缀名不正确");
}
System.out.println("后续代码");
}
public static void readFile(String fileName) throws IOException {
if(!fileName.equals("d:\\a.txt")){
throw new FileNotFoundException("文件的后缀不是d:\\a.txt");
}
System.out.println("路径没有问题,读取文件");
}
运行结果:
2.4finally
2.4.1作用:
无论异常是否发生,最后的finally代码块中的内容一定会被执行到
2.4.2基本格式:
try{
可能出现异常的代码
}catch{
异常的处理逻辑
}finally{
代码块的内容一定会执行
}
2.4.3注意事项:
- finally不能单独使用,要和try……catch一起使用
- finally一般用于资源释放
2.4.4代码示例:
public static void main(String[] args) {
try {
readFile("d:\\a.tx");
} catch (IOException e) {
e.printStackTrace();
}finally {
System.out.println("资源释放");
}
}
public static void readFile(String fileName) throws IOException {
if(!fileName.equals("d:\\a.txt")){
throw new FileNotFoundException("文件的后缀不是d:\\a.txt");
}
System.out.println("路径没有问题,读取文件");
}
运行结果:
2.5异常注意事项
2.5.1多个异常使用捕获如何处理
- 多个异常分别处理
代码示例:
public static void main(String[] args) {
try{
int [] arr = {1,2,3};
System.out.println(arr[3]);
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
try{
List<Integer> list = List.of(1,2,3);
System.out.println(list.get(3));
}catch (IndexOutOfBoundsException e){
e.printStackTrace();
}
System.out.println("后续代码");
}
- 多个异常一次捕获,多次处理
注意:
一个try中有多个catch,catch里面定义的异常变量,如果有子父类关系,子类必须写在上面
代码示例:
public static void main(String[] args) {
try{
int [] arr = {1,2,3};
System.out.println(arr[3]);
List<Integer> list = List.of(1,2,3);
System.out.println(list.get(3));
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}catch (IndexOutOfBoundsException e){
e.printStackTrace();
}
System.out.println("后续代码");
}
运行结果:
- 多个异常一次捕获,一次处理
public static void main(String[] args) {
try{
int [] arr = {1,2,3};
System.out.println(arr[3]); //ArrayIndexOutOfBoundsException
List<Integer> list = List.of(1,2,3);
System.out.println(list.get(3)); //IndexOutOfBoundsException
}catch (Exception e){
e.printStackTrace();
}
System.out.println("后续代码");
}
运行结果:
2.5.2finally中的return语句
如果finally中有return语句,那么永远返回finally中的结果
public static void main(String[] args) {
int k = 10;
int ret = get();
System.out.println(ret);
}
public static int get(){
int a = 10;
try{
return a;
}catch (Exception e){
System.out.println(e);
}finally {
a = 100;
return a;
}
}
运行结果:
100
2.5.3子父类异常
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类一样的异常或者是父类异常的子类或者不抛出异常
- 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常,此时子类产生该异常,只能进行捕获处理,不能声明抛出
示例:
public void show01() throws NullPointerException,ClassNotFoundException{
}
public void show02() throws IndexOutOfBoundsException{
}
public void show03() throws IndexOutOfBoundsException{
}
public void show04(){
}
}
class Zi extends Fu{
//子类重写父类方法时,抛出和父类一样的异常
public void show01() throws NullPointerException,ClassNotFoundException{
}
//子类重写父类方法时,抛出父类异常的子类
public void show02() throws ArrayIndexOutOfBoundsException{
}
//子类重写父类方法时,可以不抛出异常
public void show03(){
}
//父类没有异常,子类中有异常时,只能用try……catch
public void show04(){
try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
3.自定义异常
3.1作用
在开发业务的过程中往往需要自定义异常
3.2格式
public class XXXException extends Exception | RunTimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
3.3注意
- 自定义异常,必须继承Exception或者RunTimeException
- 继承Exception,那么自定义的异常就是编译期异常,如果方法内部出现了编译期异常,要么throws,要么try……catch
- 继承RunTimeException,那么自定义的异常为运行期异常,无需处理,交给Java虚拟机来处理(中断处理)
3.4代码示例
public class RegisterException extends Exception{
public RegisterException(){
super();
}
public RegisterException(String message){
super(message);
}
}
public class Demo01RegisterException {
static String [] userNames = {"张三","李四","王五"};
public static void main(String[] args) throws RegisterException {
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的用户名:");
String str = sc.nextLine();
checkUserName(str);
}
public static void checkUserName(String username) throws RegisterException {
for(String name:userNames){
if(username.equals(name)){
throw new RegisterException("该用户已被注册");
}
}
System.out.println("注册成功");
}
}
运行结果: