Java之异常

什么是异常?

程序运行过程中,由于程序中数据不合法,发生了不正常的情况,造成程序中断向下执行,最终导致JVM【虚拟机】非正常终止

异常的存在形式?

以异常类型的对象存在的,对象携带了异常相关的信息【程序中异常一旦发生就会终止向下运行】

异常的体系

编译时异常

java 复制代码
public class ExceptionDemo1 {
    public static void main(String[] args) {
//日期格式对象
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//书写代码时,代码没有问题,但发生:错误提示(当前位置可能会发生异常)
     Date date = sdf.parse("2022-11-07");//编译时异常
    }
}
-------------------------------------
改1:
public class ExceptionDemo1 {
    public static void main(String[] args) throws ParseException {
//日期格式对象
 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//书写代码时,代码没有问题,但发生:错误提示(当前位置可能会发生异常)
 Date date = sdf.parse("2022-11-07");//编译时异常
    }
}
-------------------------------------------
改2:
public class ExceptionDemo1 {
    public static void main(String[] args) {
     //日期格式对象
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//书写代码时,代码没有问题,但发生:错误提示(当前位置可能会发生异常)
     try {
         Date date = sdf.parse("2022-11-07");//编译时异常
    } catch (ParseException e) {
     throw new RuntimeException(e);
        }
    }
}

运行时异常(难处理):在编译时不检查

java 复制代码
public class ExceptionDemo3 {
    public static void main(String[] args) {
        String name = null;
        //要处理method方法中抛出的异常
        method(name);

    }

    public static void method(String name) {
        //校验:参数不能为空
        if(name == null ||"".equals(name)){
            throw new RuntimeException("参数不能为空!");
            //throw代码后面不能写任意代码
            //System.out.println("当前代码不能执行");//报错
        }
        System.out.println("你好");//可以写
    }
}
/**
Exception in thread "main" java.lang.RuntimeException: 参数不能为空!
	at com.ExceptionDemo3.method(ExceptionDemo3.java:14)
	at com.ExceptionDemo3.main(ExceptionDemo3.java:7)*/

虚拟机默认处理异常?

  • 当前发生异常的代码位置处,有处理异常的代码,那么异常就会被处理掉,程序继续执行
  • 当前发生异常的代码位置处,没有处理异常的代码(程序中没有处理异常的代码),最终异常会抛出给JVM来处理

JVM处理异常的方式:

  1. 打印异常的信息(异常的类型、异常发生的位置、异常的原因)

  2. JVM停止

异常处理的方式

1. 声明:throws

遇到异常发生了,自己不处理,交给别人处理

最终还是需要有一个位置使用try...catch来处理异常

结论:在main方法中,只能使用try...catch

java 复制代码
使用声明的方式处理异常:
//使用声明的方式处理异常,声明是书写在方法定义上
修饰符号  返回值类型 方法名(参数类型 参数,...) throws 异常类1 , 异常类2 , .... 
{
    
}
例如:
//在定义方法时,使用声明的方式处理异常
public void method(String name) throws NullPointerException {
   
}
java 复制代码
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExceptionDemo1 {
    public static void main(String[] args) {
        //自己处理异常
     //   method1(null);
        
        
        //method2方法中声明的异常,需要在main方法中处理掉,不处理就会爆红
        method2();
    }

    //运行时异常:RuntimeException类(父类)
    //子类:NullPointerException
    public static void method1(String param) throws RuntimeException {//声明异常
        //可能会发生:空指针异常 NullPointerException
        System.out.println(param.length());

        //可能会发生:索引越界异常 IndexOutOfBoundsException
        System.out.println(param.charAt(100));

        //上面两个异常都是运行时异常,有共同的父类,我们可以使用父类进行声明【多态】
    }

    //编译时异常:Exception类(父类),在程序编译的时候就会爆红
    //子类:ParseException
    public static void method2() throws ParseException {
        //日期格式对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //针对编译时异常,必须有异常处理代码(声明,捕获)
        Date date = sdf.parse("2022/5/4");
    }
}

2. 捕获:try...catch

遇到异常发生了,自己处理

阻止异常的传递,能让代码继续往下运行

格式:
java 复制代码
a.多个异常,每个异常单独处理
try{
    异常1
}catch(异常1){ }
try{
    异常2
}catch(异常2){ }

b.多个异常,一次捕获,多次处理(注意:如果多个异常有继承关系,父类异常要放在子类异常后面,建议使用)
try{
    异常1
    异常2
}catch(异常1){
}catch(异常2){
}

c.多个异常,异常一次捕获,一次处理
try{
    异常1
    异常2
}catch(Exception e){
}
java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExceptionDemo3 {
    private static final Logger logger = LoggerFactory.getLogger("ExceptionDemo3");
    public static void main(String[] args) {
        String strDate = "2025年10月1日";
        try{
            //监视可能会发生异常的代码
            //调用的方法可能会发生异常(自己处理)
            Date birthday = method(strDate);
            System.out.println("生日:" + birthday);
        }catch(Exception e){//处理异常:拿异常对象类型和当前定义的异常类型进行匹配(类型相同 或 是父类型)
            System.out.println("处理异常");
            e.printStackTrace();

            //在日志中记录下异常
            logger.error(e.getMessage());

        }
    }
    private static Date method(String strDate) throws ParseException {
        //格式化对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.parse(strDate);
    }
}

throws和throw的区别

throws :

用在方法声明后面,跟的是异常类名

表示声明异常,调用该方法有可能会出现这样的异常

异常对象有JVM创建

throw : 抛出 (手动引发异常)【还没学】

用在方法体内

表示手动抛出异常对象,告知调用者数据传入有误

异常对象我们自己创建

java 复制代码
程序员手动创建一个异常对象,并招抛出给调用者
//把创建的异常类对象抛出给调用者 
 throw new RuntimeException("参数不能为空");
注意:

1.抛出异常的格式必须在方法的内部完成

2.如果手动抛出异常,下面的代码无法执行

java 复制代码
public class ExceptionDemo2 {
    public static void main(String[] args) {
        String name = null;

        //处理method方法抛出的异常
        try{
            method(name);
        }catch(Exception e){
            System.out.println(e.getMessage());
        }

    }
    public static void method(String name){
        //校验:参数不能为空
        if(name == null || "".equals(name)){
            throw new RuntimeException("参数不能为空!");
            //在throw代码后面不能书写任意代码
//            System.out.println("当前代码无法执行");
        }
        System.out.println(name);//在括号外面可以写
    }

}

异常的解决方式在开发中怎么解决?

自定义方法(程序员自己写的方法),通常都可以使用:声明

  • 方法体内代码比较清爽(阅读性好)
  • 把异常统一抛出到main方法中,进行统一的处

捕获的使用场景:

  • main方法中只能使用捕获
  • 父类型中的方法不支持throws,在子类重写方法时,重写的方法只能使用:捕获【还没学】
java 复制代码
 public class Demo  extends Thread{
         //重写方法
         public void run(){
             try {
                 Thread.sleep(100);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }

Throwable类中常用方法

Throwable类 //异常的顶层父类型

子类:Error类(错误类)

//异常处理无法解决错误

子类:Exception类(异常类)

//可以使用异常处理解决(保证程序运行过程中不会中断)

编译时异常:Exception类
运行时异常:RuntimeException类 (继承了Exception)

Throwable的成员方法:

java 复制代码
public String getMessage()   //返回throwable的详细消息字符串
public String toString()     //返回此可抛出的简短描述
public void printStackTrace()  //把异常的错误信息输出在控制台
java 复制代码
public class ExceptionDemo3 {
    private static final Logger logger = LoggerFactory.getLogger("ExceptionDemo3");
    public static void main(String[] args) {
        String strDate = "2025年10月1日";
        try{
            //监视可能会发生异常的代码
            //调用的方法可能会发生异常(自己处理)
            Date birthday = method(strDate);
            System.out.println("生日:" + birthday);
        }catch(Exception e){//处理异常:拿异常对象类型和当前定义的异常类型进行匹配(类型相同 或 是父类型)
            System.out.println("处理异常");

            //toString()把异常对象转换为字符串
            System.out.println(e.toString());
            //java.text.ParseException: Unparseable date: "2025年10月1日"

//            e.printStackTrace();//把异常的错误信息输出在控制台,红色的

            //在日志中记录下异常
            logger.error(e.getMessage());
//   2026-01-19 11:10:04.652 [ERROR]  ExceptionDemo3 [main] : Unparseable date: "2025年10月1日"


        }
    }
    private static Date method(String strDate) throws ParseException {
        //格式化对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.parse(strDate);
    }
}

自定义异常:

  • 程序员自己编写的异常类
  • 解决问题: JDK提供的异常类在命名上做不到见名其知意,通常在开发中程序员会自定义自己的异常类(见名其知意)
java 复制代码
public 自定义异常类 extends Exception{ //当前自定义异常类为:编译时异常
      public 自定义异常类(){
          //super();//调用父类中的无参构造方法
      }
      public 自定义异常类(String message){
          super(message);
      }
  }
  
  public 自定义异常类 extends RuntimeException{ //当前自定义异常类为:运行时异常
      
  }
java 复制代码
//自定义异常类
public class AgeOutOfBoundsException extends RuntimeException{
    public AgeOutOfBoundsException() {
    }

    public AgeOutOfBoundsException(String message) {
        super(message);
    }
}
java 复制代码
public class ExceptionDemo7 {
private static final Logger logger = LoggerFactory.getLogger("ExceptionDemo7类");
    //自定义异常处理
    public static void main(String[] args) {
        try {
            printInfo("熊大", 9);
        } catch (NullPointerException e){
            System.out.println("处理空值异常");
        }catch (AgeOutOfBoundsException e){
            System.out.println("处理年龄超出范围异常");
            //记录到日志中
            logger.error(e.getMessage());
            /**
             * 处理年龄超出范围异常
             * 2025-07-27 22:23:37.295 [ERROR]  ExceptionDemo7类 [main] : 传递的值为:9,传递的年龄必须是18~50之间
             */

        }catch (RuntimeException e){
            System.out.println("处理其他运行异常");
        }catch (Exception e){
            System.out.println("可以处理任何异常");
        }
    }
    //因为异常默认的处理方式就是:当前没有异常处理,抛出异常
    public  static void printInfo(String  name , Integer age){
        //校验:传入的数据不能为空
        if(name == null || "".equals(name)){
            throw  new NullPointerException("传递的姓名不能为空");
        }
        if(age < 18 || age > 50){
            //使用自定义异常
            throw new AgeOutOfBoundsException("传递的值为:"+age+",传递的年龄必须是18~50之间");
        }
        System.out.println("姓名:"+name);
        System.out.println("年龄:"+age);
    }
}
java 复制代码
//自定义异常类
public class ExceptionDemo6 extends RuntimeException {
    public ExceptionDemo6() {
    }
    public ExceptionDemo6(String message) {
        super(message);
    }

}
class ExceptionDemo7{
    //使用自定义异常处理
    public static void main(String[] args) {
        try {
            printInfo("熊大", 88);
        }catch (Exception e){
            System.out.println("运行时异常");//运行时异常
            System.out.println(e.getMessage());//传递的值为:88传递的年龄必须是18~50之间
        }

    }
    
    public static void printInfo(String msg, int num){
        //校验:传递的数据不能为空
        if(msg == null || "".equals(msg)){
            throw new NullPointerException("传递的姓名不能为空");
        }
        if(num < 18 || num > 50){
            //使用了自定义异常
            throw new ExceptionDemo6("传递的值为:"+num + "传递的年龄必须是18~50之间");
        }
        System.out.println("姓名:"+ msg);
        System.out.println("年龄:" + num);
    }

}

异常处理解决程序中的什么问题?

当程序中发生异常后,确保程序不能中断(跳过异常部分的代码,执行后续的代码)

异常处理怎么使用

1、声明:throws 自己不处理交给他人处理

2、捕获:try...catch 自己处理

java 复制代码
public void method() throws 异常类 {
      //有编译时异常(编译时就会提示):throws、try...catch
  }

  //默认的异常处理方式:向上抛出
  public void show() {
      //有运行时异常: try...catch | throws
  }
  
  publi void hello(){
      try{
          
          //可能会发生异常的代码
          
          
      }catch(Exception e){
          //处理异常
          //日志记录异常信息
      }
  }

异常在使用中的注意细节?

java 复制代码
try{
      
  }catch(异常子类 e){
      
  }catch(异常子类 e){
      
  }...
   catch(异常父类 e){
       
  } 
  
  main方法只能使用:try..catch
      
  
  //自定义异常
  public class 自定义异常类 extends RuntimeException{
      public 自定义异常类(){}
      public 自定义异常类(String message){
          super(message);
      }
  }   
  
  if( 参数 == null){
      //手动引发异常,并抛出
      throw new 自定义异常类("异常消息");
  }
相关推荐
郝学胜-神的一滴2 小时前
Python对象的自省机制:深入探索对象的内心世界
开发语言·python·程序人生·算法
Sylvia33.2 小时前
网球/羽毛球数据API:专业赛事数据服务的技术实现
java·前端·websocket·json
说私域2 小时前
全民电商时代下的链动2+1模式与S2B2C商城小程序:社交裂变与供应链协同的营销革命
开发语言·人工智能·小程序·php·流量运营
爱丽_2 小时前
Spring 框架
java·后端·spring
期待のcode2 小时前
浅堆深堆与支配树
java·jvm·算法
小北方城市网2 小时前
SpringBoot 集成 RabbitMQ 实战(消息队列):实现异步通信与系统解耦
java·spring boot·后端·spring·rabbitmq·mybatis·java-rabbitmq
且去填词2 小时前
三色标记法与混合写屏障:Go GC 垃圾回收全流程解析
开发语言·算法·golang·三色标记法·gogc·屏障技术
froginwe112 小时前
`.addClass()` 方法详解
开发语言
机器视觉知识推荐、就业指导2 小时前
Qt 6 所有 C++ 类(官方完整清单 · 原始索引版)
开发语言·c++·qt