【重拾Java系列】—— 异常

发布于:2023-01-23 ⋅ 阅读:(483) ⋅ 点赞:(0)

异常介绍

  • 什么是异常?

Java语言中,将程序执行中发生的不正常情况成为“异常”。【语法错误和逻辑错误异常】

  • 两类异常:
    在这里插入图片描述

(1) Error:Java虚拟机无法解决的严重问题,会导致程序崩溃。例如:JVM系统内部错误,资源耗尽。
(2) Exception:因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:网络中断,空指针访问,读取不存在的文件等。

运行时异常可以不处理,编译时异常必须处理

  • 异常体系图:
    在这里插入图片描述

常见的运行时异常

(1)NullPointerException

当应用程序视图在需要对象的地方使用null,抛出该异常【使用的对象可能为空

(2)AritmeticException
当出现异常的运算条件时,抛出此异常。【不满足数学规律

(3)ArrayIndexOutOfBoundsException
数组下标越界【数组索引不满足条件】

(4)ClassCastException
类型转化异常,当试图将对象强制转化为不是实例的子类时,抛出该异常。

//假设B类和C类都继承A类
class A{}
class B extends A{}
class C extends A{}
//在测试类创建类的实例
class Test{
	public static void main(String [] args){
		A b = new B(); //向下转型创建B的对象
		A a = (A)a; //向上转型创建A的对象
		//一下为错误内容
		C c = (C)b; //b 和 C类不存在继承关系,所以会抛出强制类型转化异常
	}
}

(5)NumberFormatException
数字格式不正确异常,当应用程序试图将 字符串转化为一种数值类型,但该字符串不能转化为适当格式 时,抛出该异常

int num = Interger.parseInt("abc");

常见的编译异常

  • 编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译。
  • 常见的编译异常:【网络、数据库、文件异常】

SQLException 操作数据库时出现的异常
IOException 操作文件时发生的异常
FileNotFoundException 对不存在的文件操作发生的异常
ClassNotFoundException 加载不存在的类时,出现的异常
EOFException 操作文件,到文件末尾发生异常
IllegalArguementException 参数异常

异常处理

  • 当异常发生时,对异常处理的方式,主要有一下两种

try-catch-finally

程序员在代码中捕获发生的异常,自行处理

try{
    可能存在异常的代码
}catch(Exception e){
	处理方式
}finally{
	必然要执行的代码块
}
  • 当异常发生时,系统将异常封装成Exception的对象e,传递给catch,得到异常对象后,程序员自己处理。
  • 无论try代码块是否发生异常,finally代码块中的内容都会执行,一般将释放资源的代码放在finally代码块中
  • 但catch代码块 只有try代码块发生异常时才会执行
ctrl + alt + t 快捷键
  • 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块

  • 如果异常没有发生,则顺序执行try的代码块,不会进入到catch

  • 如果希望不管是否发生异常,都执行某代码(比如关闭连接,释放资源等),则使用finally代码块

  • 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,如果发生异常,只会匹配一个catch【例如:NullPointerException在前,Exception在后】

package com.zwh.exception_;
/**
 * @author Bonbons
 * @version 1.0
 */
public class Exception01 {
public static void main(String[] args) {
    Person p = new Person();
    p = null;
    try{
        System.out.println(p.name);
        int num = 1/0;
    }catch(NullPointerException e){
        System.out.println("空指针异常" + e.getMessage());
    }catch(ArithmeticException e){
        System.out.println("算术异常" + e.getMessage());
    }catch(Exception e){
        System.out.println(e.getMessage());
    }finally{
    }
    }
}
class Person{
    String name;

    public String getName() {
        return name;
    }
}

(1)发生异常后不会继续执行try代码块中的内容,比如此时运行程序只会检测出来一个异常
在这里插入图片描述
(2)子类异常放在前面
如果将子类异常放在后面会报错。

(3)可以进行try-finally配合使用,这种用法相当于没有捕获异常,程序会直接崩掉。必须执行某个业务。

(4) finally中的内容必须要执行,即便在catch中包含 return

try{
	发生了异常;
}catch(Exception e){
	return 1;
}finally{
	return 0;
}

最后返回的仍然是0

try{
	int i = 3;
	发生异常;
}catch(Exception e){
	return i;
}finally{
	i++;
	System.out.println("i = " + i);
}

最后会打印出 i = 4,但程序返回的是3,因为在finally中没有返回语句

  • try-catch-finally的应用
    利用try输入一个整数,如果不满足条件就重新输入,直到满足条件为止
import java.util.Scanner;
public class ExceptionTest {
    static int n;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while(true){
            try{
                n = sc.nextInt();
                System.out.println("您输入的整数为: " + n);
                break;
            }catch (Exception e){
                System.out.println(e.getMessage());
                System.out.println("请重新输入一个整数:");
//                sc = new Scanner(System.in);
            }
        }
    }
}

如果没有重新创建扫描器就会陷入到死循环中,因为 使用nextInt()扫描器在输入内容结束按回车后,系统会在输入内容后自动添加上\n 或 \r,也就导致扫描器只能使用一次

高配版,顺便引出一个问题【重要指数五颗星】

package com.zwh.exception_;

import com.sun.xml.internal.ws.addressing.WsaActionUtil;

import java.util.Scanner;

/**
 * @author Bonbons
 * @version 1.0
 * 用户输入的不是一个整数就一直输入
 */
public class ExceptionTest {
    static int n;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n;
        while(true){
            System.out.println("请输入一个整数:");
            //此处利用的next()方法获取从键盘输入的内容
            try {
                n = Integer.parseInt(sc.next());
                System.out.println("您输入的整数是: " + n);
                break;
            } catch (NumberFormatException e) {
                System.out.println("您输入的并不是一个整数!");
            }
        }
    }
}

利用类型转化报错也可以达到相同的效果,我们可以发现并没有创建新的扫描器对象,经过测试next()、nextLine()方法都可以重复使用创建的扫描器对象,在使用后不会在输入的文本后面添加换行。

补充内容:
(1) next() 方法在遇到有效字符前所遇到的空格、tab 键、enter 键都不能当作结束符。所以,读到 abc 后有空格,存下第一个,读到 cba 后回车存下第二个。
(2)nextLine() 会读取中间的空格,无论是否输入了内容,只要读取到了回车就会结束。

throws

JVM 打印异常信息,退出程序
没有显示处理异常,就是默认使用了throws

在这里插入图片描述

(1)如果一个方法中的语句在运行时可能生成某种异常,但是并不能确定如何处理这些异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
(2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
(3)子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型

class Father{
	public void method() throws RunTimeException{
	}
}
class Son extends Father{
	public void method() throws ArithmeticException{
	}
}

自定义异常

  • 当程序中出现了某些“错误”,但错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。

  • 自定义异常的步骤:

定义类:自定义异常类名继承Exception(代表编译异常)或RunTimeException(代表运行异常)
通过异常类的构造器设置异常信息提示
自定义异常通常是继承RuntimeException,就是设置为运行时异常,好处是可以使用默认的处理机制 【隐式抛出异常】

package com.zwh.exception_;
import java.util.Scanner;
/**
 * @author Bonbons
 * @version 1.0
 * 自定义异常,如果用户输入的数不在18-120之间就提示异常信息
 */
public class CustomException {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Please input age: ");
        int age = sc.nextInt();
        //判断年龄是否符合规定的范围
        if(age < 18 || age > 120){
            throw new UserException("ageBoundException");
        }
        System.out.println("你的年龄范围正确!");
    }
}

class UserException extends RuntimeException {
    //自定义异常类的构造器
    public UserException(String message) {
        super(message);
    }
}

throws 和 throw 的异常

  • throws:异常处理的一种方式,在方法声明处使用,其后为异常类型
  • throw:用于手动生成异常对象的关键字,在方法体中,其后为异常对象
public void fun(){
	throw new Exception();
}

一个小案例

  • 案例描述:编写应用程序,接收命令行的两个参数(整数),计算两数相除。计算两个数相除,要求使用方法cal(int n1,int n2),对数据格式不正确、缺少命令行参数、除0进行异常处理。
public class ExceptionWork01 {
    public static void main(String[] args) {
        try {
        	//通过args数组传入参数
            if(args.length != 2){
                throw new ArrayIndexOutOfBoundsException("参数个数不正确!");
            }
            //将args接收到的参数转化为整型
            int n1 = Integer.parseInt(args[0]);
            int n2 = Integer.parseInt(args[1]);
            //调用两个数相除的方法
            double res = cal(n1, n2);
            System.out.println("计算结果为: " + res);
        } catch (NumberFormatException e) {
            System.out.println("参数格式错误,应该为整数!");
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e.getMessage());
        }catch (ArithmeticException e){
            System.out.println("出现了零异常!");
        }
    }
	//除法方法
    public static double cal(int n1, int n2){
        return (double)n1 / n2;
    }
}

在这里插入图片描述
代码页点击这里,在红框栏输入参数即可
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到