Java-异常

本文详细介绍了Java中的异常处理机制,包括异常的分类(Error、Exception和RuntimeException),编译时异常与运行时异常的区别,以及如何通过throws、throw和try-catch语句进行异常的捕获和处理。同时涵盖了自定义异常的创建和使用方法。
摘要由CSDN通过智能技术生成

image-20240119215029625

1认识

什么是异常?

  • 异常是程序在"编译" 或者 "执行"的过程中可能出现的问题; 注意:语法错误不算在异常体系中

  • 比如:数组索引越界、空指针异常、日期格式化异常等

为什么要学习异常?

  • 异常一旦出现了,如果没有提前处理,程序就会退出 JVM 虚拟机 而终止;

  • 研究异常并且避免异常,然后提前处理异常,体现的是程序的安全性,健壮性;

image-20240119220031323

Throwable:

  • 不管是错误,还是异常,都是可抛出的;

Error:

  • 系统级问题、JVM退出等,代码无法控制;
  • 所有错误只要发生,Java程序只有一个结果,那就是终止程序的执行,退出JVM,错误是不能处理的;

Exception

  • RuntimeException:运行时异常不要求检查的异常,运行时异常发生概率未受检异常或者非受控异常

    • 空指针异常,数组索引越界异常
  • Exception的直接子类 ExceptionSubClass ,运行时异常发生概率;受检异常或者受控异常(非运行时异常,编译时异常

    • 日期格式异常

image-20240119222235118

实例:

public class ExceptionTest {
    public static void main(String[] args) {
        System.out.println(1 / 0);	//ArithmeticException 

        // 这里的HelloWorld没有输出,没有执行。
        System.out.println("Hello World!");
    }
}
  • 产生了ArithmeticException 异常,底层 new 了一个ArithmeticException异常对象,然后抛出;

  • 这个异常ArithmeticException抛给了main方法,main方法没有处理,将这个异常自动抛给了 JVM;JVM最终终止程序的执行。

  • 此时System.out.println(“Hello World!”); 并不会执行。

2运行时异常

没有考虑好业务需求 与 不严谨的编程逻辑,造成程序异常

image-20240119223315264

public class RuntimeException {
    public static void main(String[] args) {
        //1.ArrayIndexOutOfBoundsException  数组越界
        String[] arr = {"1","2"};
//        System.out.println(arr[2]);

        //2.空指针异常 NullPointerException
        String s = null;
        System.out.println(s);
//        System.out.println(s.length());

        //3.类型转换异常 : ClassCastException
        Object o  = "23";
//        Integer integer = (Integer) o;    报错

//        if (o instanceof String){
//            String s1 = (String) o;
//            System.out.println(1);
//        }else if (o instanceof Integer){
//            int i = (int) o;
//            System.out.println(i);
//        }

        //4.数字操作异常  ArithmeticException
//        Integer integer = 10/0;

        //5.数字转换异常  NumberFormatException
        String s3 = "32ab";
//        Integer i = Integer.valueOf(s3);
    }
}
3编译时异常

image-20240119223858082

编译时异常的作用

  • 在编译阶段就爆出一个错误,目的在于提醒不要出错!!!
  • 编译时异常是可遇不可求;
  • idea出现红色波浪线提醒
public class JavacException {
    public static void main(String[] args) throws ParseException {
        String d = "2023-5-16 13:02:56";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        throw new ParseException("Unparseable date: \"" + source + "\"" ,
//                pos.errorIndex);
        Date date = sdf.parse(d);
        System.out.println(date);
    }
}
4异常处理
4.1默认处理

默认处理机制:出现异常,直接程序死亡

public class Demo {
    public static void main(String[] args) {
        System.out.println("程序开始");
        divide(10,2);
//        divide(11,0);
        System.out.println("程序结束");
    }

    public static void divide(int a , int b){
        int d = a/b;
        System.out.println(d);
    }
}

分析

  • 1.默认会在出现异常的代码,那里自动的创建一个异常对象(ArithmeticException);

  • 2.异常会从方法中出现的点,抛出给调用者,调用者最终会抛出给JVM虚拟机;

  • 3.虚拟机接受到异常对象后,先在控制台直接输出异常栈信息数据;

  • 4.直接从当前执行的异常点干掉当前程序;

  • 5.后续代码就没有机会执行,程序已经死亡;

4.2异常处理

异常处理的三种方式:抛出、捕获和处理;

4.2.1抛出

1.throws

  • 用在方法上,可以将方法内部出现的异常抛出去 给本方法的调用者处理;

  • Exception 逐层抛出,发生异常的方法,自己不处理异常,如果异常最终抛给 JVM虚拟机,将引起程序死亡;

  • 注意

    • throws RuntimeException 默认就存在
    • 方法内部 throw 编译时异常(Exception的直接子类),该方法必须抛出去;而运行时异常不必抛出

格式(规范):

方法 throws Exception {

}

public class ThrowsDemo {
	public static void main(String[] args) throws Exception{
        String s = "2023-5-16 13:22:36";
        func1(s);
    }

    public static void func1(String s) throws Exception {       //逐级添加ParseException ...
        InputStream inputStream = new FileInputStream("D:/meinv.jpg"); //FileNotFoundException: D:\meinv.jpg (系统找不到指定的文件。)
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(s);
        System.out.println(date);
    }
}

2.throw

  • 抛出异常是指在代码中使用throw关键字来主动抛出异常;

  • 当程序执行到throw语句时,会立即终止当前代码块的执行,并将异常抛给上一级调用栈(调用者);

    throw new IlleagalException("异常信息");  // 自定义继承Exception的类
    
  • 抛出异常时,需要创建一个异常对象,并将其抛出。异常对象可以是任何继承自Throwable类的对象,例如Exception类或RuntimeException类的子类。

throwsthrow区分

  • throws 放置在方法声明,抛出方法内部的异常
  • throw 在方法内部创建一个异常对象,并从此处抛出
4.2.2捕获并处理

try-catch

  • 程序执行到try代码块时,如果发生异常,程序捕获到异常,会跳转到相应的catch代码块进行处理;
  • 捕获异常时,如果发生的异常类型与某个catch代码块相匹配,则执行该代码块的代码;
  • 如果捕获异常时,没有与catch的异常匹配,那异常将会传递到 上一级调用栈 中进行处理;

格式

try {
    // 可能会抛出ArithmeticException异常的代码
} catch (ArithmeticException e) {
    // 处理ArithmeticException异常
} finally {
    // 执行清理操作,例如关闭文件或释放资源
}
  • catch后面的小括号中的类型可以是 具体的异常类型,也可以是该异常类型的 父类型
  • catch可以写多个。建议catch的时候,精确的一个一个处理。这样有利于程序的调试。
  • catch写多个的时候,从上到下,必须遵守 从小到大
  • 可以通过finally代码块来执行一些清理工作,例如关闭文件释放资源等。
public class TryCatchDemo {
    public static void main(String[] args){
        System.out.println("---------程序开始---------");
        String s = "2023-5-16 13:22:36";
        parseTime(s);
        System.out.println("---------程序结束---------");
    }
    //日期时间解析
    public static void parseTime(String s){     //方法一旦出现异常,直接异常处理方法结束,但main调用者正常运行下去,只是发现第一个异常
        try {
            InputStream inputStream = new FileInputStream("D:/meinv.jpg");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = sdf.parse(s);
            System.out.println(date);
        } catch (Exception e) {
            e.printStackTrace();            //打印异常栈信息
        }
    }
}

throwstry-catch结合

方法使用throws , 调用者使用 try/catch 分析处理  底层处理情况
public class ThirdMethodDemo {
    public static void main(String[] args) {
        System.out.println("======程序开始======");
        String s = "2023-5-16 13:22:36";
        try {
            parseTime(s);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("日期解析失败");
        }
        System.out.println("======程序结束======");
    }

    public static void parseTime(String s) throws Exception{        //发现第一个异常,就选择抛掉,方法结束
        InputStream inputStream = new FileInputStream("D:/meinv.jpg");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(s);
        System.out.println(date);
    }
}

实例:输入合法定价

public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
		while(true){
              try { //非数字 抛出NumberFormatException
                  System.out.println("请输入合法的定价");
                  String s = sc.next();
                  double d = Double.valueOf(s);
                  if(d > 0){
                      System.out.println("定价:" + d);
                      break;
                  }else {
                      System.out.println("你输入的是非正数");
                  }
              } catch (NumberFormatException e) {      
                  System.out.println("您输入的数据有误,请您输入合法的数值,建议为正数");
              }
          }
    }
}
4.3finally

try-catch-finally finally内的代码一定会执行

只有System.exit(0); 只有这个可以治finally。

public class ExceptionTest {
    public static void main(String[] args) {
        try {
            System.out.println("try...");
            // 退出JVM
            System.exit(0); // 退出JVM之后,finally语句中的代码就不执行了!
        } finally {
            System.out.println("finally...");
        }
    }
}

面试:

public class ExceptionTest13 {
    public static void main(String[] args) {
        int result = m();
        System.out.println(result); //100
    }

    /*
    java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做!):
        java中有一条这样的规则:
            方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!)
        java中还有一条语法规则:
            return语句一旦执行,整个方法必须结束(亘古不变的语法!)
     */
    public static int m(){
        int i = 100;
        try {
            // 这行代码出现在int i = 100;的下面,所以最终结果必须是返回100
            // return语句还必须保证是最后执行的。一旦执行,整个方法结束。
            return i;
        } finally {
            i++;
        }
    }
}

反编译之后的效果

public static int m(){
    int i = 100;
    int j = i;
    i++;
    return j;
}
5自定义异常

1.自定义编译时异常

  • 定义一个异常类 extends Exception (Exception的直接子类)
  • 重写构造器
  • 在出现异常的地方用 throw new 自定义对象抛出
public class AgeIlleagalException extends Exception{
    public AgeIlleagalException(){

    }
    public AgeIlleagalException(String message) {
        super(message);
    }
}

2.自定义运行时异常

  • 定义一个异常类 extends RuntimeException(运行时异常)
  • 重写构造器
  • 在出现异常的地方用 throw new 自定义对象抛出
public class AgeIlleagalException2 extends RuntimeException{
    public AgeIlleagalException2(){

    }
    public AgeIlleagalException2(String message) {
        super(message);
    }
}

对比:(检查年龄)

public class Test {
    public static void main(String[] args){
        System.out.println("------------程序开始------------");
        try {
            checkAge(23);
        } catch (AgeIlleagalException e) {
            e.printStackTrace();
        }

        try {
            checkAge2(202);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("------------程序结束------------");
    }

    /**
     * 编译时异常
     * @param age   年龄
     * @throws AgeIlleagalException 自定义编译时异常
     */
    public static void checkAge(int age) throws AgeIlleagalException {
        if(age < 0 || age > 200){
            //throws 放置在方法声明,抛出方法内部的异常
            //throw  在方法内部创建一个异常对象,并从此处抛出
            throw new AgeIlleagalException(age + " is illeagal!");
        }else {
            System.out.println("年龄合法: 推荐商品给其购买~~~");
        }
    }

    /**
     * 检查年龄
     * @param age  年龄
     */
    public static void checkAge2(int age){
        if(age < 0 || age > 200){
            //throws 放置在方法声明,抛出方法内部的异常
            //throw  在方法内部创建一个异常对象,并从此处抛出
            throw new AgeIlleagalException2(age + " is illeagal!");
        }else {
            System.out.println("年龄合法: 推荐商品给其购买~~~");
        }
    }
}
参考

Java-异常

Java异常(超详细)

Java异常处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值