Java异常目录

  • 1、思维导图
  • 2、异常概述
  • 3、异常处理机制
  • 4、捕获异常 try-catch-finally
  • 4.1、try-catch-finally 使用说明
  • 4.2、处理运行时异常
  • 4.3、处理编译时异常
  • 5、声明抛出异常 throws
  • 6、抛出和捕获结合使用
  • 7、自定义异常 throw


java修改打印debug_Java异常


java修改打印debug_Java异常

1、思维导图

java修改打印debug_Java异常_03

2、异常概述

异常:在Java语言中,将程序执行中发生的不正常情况称为异常 (开发过程中的语法错误和逻辑错误不是异常)。

异常分类:

  • Error:Java虚拟机无法解决的严重问题,一般不编写针对性的代码进行处理。
  • 如:JVM系统内部错误、资源耗尽等严重情况、StackOverflowError堆栈溢出等
  • Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:空指针异常、试图读取不存在的文件、数组角标越界…
  • 编译时异常:是指编译器要求必须处置的异常,即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。对于这类异常,如果程序不处理,可能会带来意想不到的结果。
  • 运行时异常:是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException 类及它的子类都是运行时异常。比如:除数为0,数组下标越界等;对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。

对于异常一般有两种解决方法:

  • 终止程序的运行
  • 编写程序时就考虑到错误的检测、错误消息的提示,以及错误的处理:捕获异常声明抛出异常自定义异常

Java异常处理机制:捕获异常声明抛出异常

3、异常处理机制

在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的if-else分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。

Java异常处理Java采用的异常处理机制,是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁、优雅,并易于维护。

异常处理的2种方式:

  • 方式一:try-catch-finally(直接捕获处理掉)
  • 方式二:throws + 异常类型(抛出交给调用者处理)

Java提供的是异常处理:抓抛模型

  • 过程一:“抛”
  • 程序在执行过程中如果出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出(throw);一旦抛出对象以后,其后的代码就不再执行。
  • 关于异常对象的产生:
  • 系统自动生成的异常对象
  • 手动的生成一个异常对象,并抛出(throw)
  • 过程二:“抓”
  • 可以理解为异常的处理方式:① try-catch-finally ② throws

4、捕获异常 try-catch-finally

捕获异常过程:在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型去catch中进行匹配。一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。如果有finally的情况下先执行finally中的语句,然后继续执行其后的代码。

4.1、try-catch-finally 使用说明

try{…}语句块:

  • 捕获异常的第一步将可能出现异常的代码放在try语句块中
  • 在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配。

在catch语句块中是对异常对象进行处理的代码

  • 每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
  • 如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。比如: 可以用 ArithmeticException 类 作为参数的地方,就可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常,如NullPointerException(catch中的语句将不会执行)。
  • catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
  • catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面;否则报错。

finally语句块:是可选的

  • 一定会执行的代码,即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。
  • 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。
try{
...... // 可能产生异常的代码
}
catch( 异常类型1 变量名1 ){
...... // 当产生异常类型1时的处置措施
}
catch( 异常类型2 变量名1 ){
...... // 当产生异常类型2时的处置措施
}
...
finally{
...... //无论是否发生异常,一定会执行的代码【可选】
}
// 获取异常信息,返回字符串
System.out.println(e.getMessage());
// 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
e.printStackTrace();

4.2、处理运行时异常

处理运行时异常 RuntimeException

  • 常见运行时异常有:数学运算异常(如0位除数)、类型转换异常、空指针异常、数字格式异常、数组或字符下标越界异常
  • 这些类的异常的特点是:即使没有使用try和catch捕获,Java自己也能捕获,并且编译通过(但运行时会发生异常使得程序运行终止)
  • 开发中,由于运行时异常比较 常见,所以我们 通常就不针对运行时异常编写try-catch-finally
public class IndexOutException {
    public static void main(String[] args) {
        String[] arr = {"aaa", "bbb", "ccc"};
        try {
            System.out.println(arr[3]);
            System.out.println("try...");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组角标越界!");
        }
        System.out.println("方法执行结束...");
    }
}

4.3、处理编译时异常

处理编译时异常:则必须捕获,否则编译错误。

  • 常见编译时异常有:IO异常、数据库访问异常、指定类不存在异常等
  • 使用try-catch-finally处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现,转化为运行时异常。
  • try-catch-finally结构可以嵌套
// 将工程路径下的test.txt文件打印到控制台
public class IOExceptionTest {
    public static void main(String[] args) {
        try {
            FileInputStream in = new FileInputStream("test.txt");
            int len;
            len = in.read();
            while (len != -1) {
                System.out.print((char) len);
                len = in.read();
            }
            in.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println(e);
        } finally {
            System.out.println("执行其它语句...");
        }
    }
}
public void testDelete() {
    Connection conn = null;
    Statement statement = null;
    try {
        // 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 获取连接对象
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
        // 获取执行sql语句的对象
        statement = conn.createStatement();
        // sql语句
        String sql = "delete from student where id = 6";
        // 发送sql
        int i = statement.executeUpdate(sql);
        System.out.println("受影响的条数:" + i);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        // 关闭连接
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

5、声明抛出异常 throws

如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。(由JVM来处理,即默认异常操作,将会在出现异常处,终止程序运行,并返回异常栈内信息)

在方法声明中用throws语句可以声明抛出异常的列表(可以声明多个的异常),throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

public void method(String str) throws 异常A,异常B,... { 方法体 }

throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

public void readFile(String file) throws FileNotFoundException{
    ...
    // 读文件的操作可能产生FileNotFoundException类型的异常
    FileInputStream fis = new FileInputStream(file);
    ...
}
public void readFile(String file) throws IOException {
    ...
    FileInputStream fis = new FileInputStream(file);
    ...
}

重写方法不能抛出比被重写、方法范围更大的异常类型。

  • 在多态的情况下, 一般对methodA()方法的调用异常的捕获按父类声明的异常处理。
public class A {
    public void methodA() throws IOException {...} 
}

public class B1 extends A {
    public void methodA() throws FileNotFoundException {...}
}
    										
public class B2 extends A {
    //报错
    public void methodA() throws Exception {...} 
}

6、抛出和捕获结合使用

为保证程序正常执行,代码必须对可能出现的异常进行处理,需要 try-catch-finally 和 throws 结合使用。

注意:异常抛出给调用者,最终需在main()方法中处理。

java修改打印debug_java修改打印debug_04

举例:将工程路径下的test.txt文件打印到控制台

public class IOExceptionThrows {
    public static void main(String[] args) {
        IOExceptionThrows readFileTest = new IOExceptionThrows();
        try {
            readFileTest.readFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    // 抛出readFile()产生的异常,交给调用者main()处理
    public void readFile() throws IOException {
        FileInputStream in = new FileInputStream("test.txt");
        int b = in.read();
        while (b != -1) {
            System.out.print((char) b);
            b = in.read();
        }
        in.close();
    }
}
// 首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。
IOException e = new IOException();
throw e;
// 可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将会产生语法错误:
throw new String("want to throw");

7、自定义异常 throw

JDK中定义了大量的异常可以描述异常情况,但在开发中会出现特殊的问题,为了解决这个问题,Java允许用户自定义异常;抛出异常 thow:当程序查到一个错误后,创建一个适当类型异常的实例并抛出它。

  • 一般地,用户自定义异常类都是RuntimeException的子类
  • 如何自定义异常类:需要编写几个重载的构造器、提供serialVersionUID、继承于现有的异常结构。
  • 用户自己的异常类 必须继承Throwable类或其子类的实例
  • 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
// 举例:人数注册
public class MyExceptionTest {
    public void register(int num) throws MyException {
        if (num < 0) {
            //出现异常时:创建自定义的异常类的实例
            throw new MyException("人数为负值,不合理", 500);
        } else {
            System.out.println("登记成功,人数为" + num);
        }
    }

    public void manager() {
        try {
            register(-1);
        } catch (MyException e) {
            System.out.println("登记失败,出错类型" + e.getId() + "\n" + e.getMessage());
        }
        System.out.print("本次登记操作结束");
    }

    public static void main(String args[]) {
        MyExceptionTest t = new MyExceptionTest();
        t.manager();
    }
}

// 自定义异常类
public class MyException extends Exception {

    static final long serialVersionUID = 13465653435L;
    
    private int id;

    public MyException(String message, int id) {
        super(message);
        this.id = id;
    }

    public int getId() {
        return id;
    }

}

在开发中自定义异常类一般继承异常类后重新一下构造方法即可,然后交给全局异常处理器。

// 举例:springboot项目实现用户下单的业务
@Transactional
public void submit(Orders orders) {
    ...
    // 防止购物车为空时点击下单
    if (shoppingCarts == null || shoppingCarts.size() == 0) {
        throw new CustomException("购物车为空,不能下单!");
    }
    ...
}

// 自定义异常类:CustomException
public class CustomException extends RuntimeException{
    public CustomException(String message) {
        super(message);
    }
}

// 全局异常处理器
@Slf4j
@ResponseBody // 返回JSON数据
@RestControllerAdvice
public class GlobalExceptionHandler {
   
     /**
     * 处理CustomException自定义业务异常
     */
    @ExceptionHandler(CustomException.class)
    public R<String> exceptionHandler(CustomException ex){
        return R.error(ex.getMessage());
    }
}

总结:

java修改打印debug_java修改打印debug_05


世界上最遥远的 距离,是我在 if 里你在 else 里,似乎一直相伴又永远分离;

世界上最痴心的 等待,是我当 case 你是 switch,或许永远都选不上自己;

世界上最真情的 相依,是你在 try 我在 catch。无论你发神马脾气,我都默默承受,静静处理。到那时,再来期待我们的 finally