Java-异常

本文深入讲解Java中的异常处理机制,包括异常的基本概念、异常的分类、常见异常类型、异常处理方式(try-catch-finally与throws)、自定义异常以及throw与throws的区别等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常介绍

基本概念

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

package com.pero.exception_;

/**
 * 异常处理入门
 *
 * @author Pero
 * @version 1.0
 */
public class Exception01 {
    public static void main(String[] args) {

        int a1 = 10;
        int a2 = 0;

        // a1 / a2 ,因为分母为0,程序会(抛出)异常  AithmeticException
        // 当抛出异常后程序就退出,崩溃了
        //异常处理解决该问题,使用try-catch异常处理机制来解决
        //从而保障健壮性
        //选中代码块->ctrl+alt+t->选中try-catch
        //后续代码继续执行
        try {
            int res = a1 / a2;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("程序继续执行");


    }
}

1.执行过程中所发生的异常事件可分为两类;

1)Error(错误):Java虚拟机无法解决的严重问题。Error是严重错误,程序会崩溃。

2)Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。分为两大类:运行时异常和编译时异常。

2.运行时异常,编译器检查不出来。一般是指编译时的逻辑错误,是程序员应该避免其出现的异常;

3.对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响;

4.编译时异常,是编译器要求必须处理的异常。

package com.pero.exception_;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author Pero
 * @version 1.0
 */
public class Exception02 {
    public static void main(String[] args) {

        try {
            FileInputStream fis;
            fis = new FileInputStream("d:\\aa.jpg");
            int len;
            while ((len = fis.read()) != -1){
                System.out.println(len);
            }
            fis.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

常见的运行时异常

1)NullPointerException 空指针异常;

当应用程序试图需要对象的地方使用null时,抛出该异常。

package com.pero.exception_;

/**
 * 常见异常-空指针异常
 *
 * @author Pero
 * @version 1.0
 */

public class Exception03 {
    public static void main(String[] args) {

        String name = null;
        System.out.println(name.length());  //抛出空指针异常
        //Exception in thread "main" java.lang.NullPointerException
        //	at com.pero.exception_.Exception03.main(Exception03.java:15)
    }
}

2)ArithmeticException数学运算异常;

当出现异常的运算条件时,抛出此异常

package com.pero.exception_;

/**
 * 常见运行异常-数学运算异常
 *
 * @author Pero
 * @version 1.0
 */
public class Exception04 {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;

        double result = a / b;  //抛出数学运算异常
        //Exception in thread "main" java.lang.ArithmeticException: / by zero
        //	at com.pero.exception_.Exception04.main(Exception04.java:14)

        System.out.println(result);

    }
}

3)ArrayIndexOutOfBoundsException数组下标越界异常;

用非法索引访问数组时抛出的异常。如果索引为负数或者大于等于数组的大小,则该索引为非法索引。

package com.pero.exception_;

/**
 * 常见运行异常-数组下标越界异常
 *
 * @author Pero
 * @version 1.0
 */
public class Exception05 {
    public static void main(String[] args) {

        String name = "smith";
        for (int i = 0; i <= name.length(); i++) {
            System.out.println(name.charAt(i));
        }
        //当运行至name.charAt(5)时,数组下标越界抛出此异常
        //s
        //m
        //i
        //t
        //h
        //Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 5
        //	at java.lang.String.charAt(String.java:658)
        //	at com.pero.exception_.Exception05.main(Exception05.java:14)
    }
}

4)ClassCastException类型转换异常;

当试图将对象强制转换为不是实力的子类时,抛出该异常。

package com.pero.exception_;

/**
 * 常见运行异常-类型转换异常
 *
 * @author Pero
 * @version 1.0
 */
public class Exception06 {
    public static void main(String[] args) {
        A b = new B();
        B b2 = (B) b;  //可以
        C c2 = (C) b;  //不可以,抛出类型转换异常
        //Exception in thread "main" java.lang.ClassCastException: com.pero.exception_.B cannot be cast to com.pero.exception_.C
        //	at com.pero.exception_.Exception06.main(Exception06.java:13)
    }
}
class A{}
class B extends A{}
class C extends A{}

5)NumberFormatException数字格式不正确异常

当程序试图将字符串转换成一种数值类型,但该字符不能转换为适当格式时,抛出该异常

package com.pero.exception_;

/**
 * 常见运行异常-数字格式不正确异常
 *
 * @author Pero
 * @version 1.0
 */
public class Exception07 {
    public static void main(String[] args) {
        String number = "12345678";

        //将String  转换成  int
        int number1 = Integer.parseInt(number);

        String number2 = "正在学习";
        int number3 = Integer.parseInt(number2);  //抛出数字格式不正确异常
        //Exception in thread "main" java.lang.NumberFormatException: For input string: "正在学习"
        //	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        //	at java.lang.Integer.parseInt(Integer.java:580)
        //	at java.lang.Integer.parseInt(Integer.java:615)
        //	at com.pero.exception_.Exception07.main(Exception07.java:17)
    }
}

编译异常

编译异常是指在编译期间就必须处理的异常,否则代码不能通过编译。

常见的编译异常

1)SQLException  //操作数据库时,查询表可能发生的异常

2)IOException  //操作文件时发生的异常

3)FileNotFoundException  //当操作一个不存在的文件时发生的异常

4)ClassNotFoundException  //加载类而该类不存在时发生的异常

5)EOFException  //操作文件到文件末尾发生异常

6)IllegalArguementException  //参数异常

异常处理的方式(二选一)

1)try-catch-finally

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

try{

        代码/可能有异常

}catch(Exception e){

        //捕获异常

        1.当异常发生时,系统将一场封装成Exception对象e,传递给catch

        2.得到异常对象后,程序员自己处理

        3.如果没有发生异常,catch代码块不执行

}finally{

        //不管try代码块是否有异常发生,始终要执行finally

        //通常将释放资源的代码放进finally

}

2)throws

将发生异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM

调用:JVM  ->  main  ->  方法f1  ->  方法f2

向上抛出异常:方法f2  —throws—>  方法f1  —throws—>  main  —throws—>  JVM

顶级JVM处理异常:①输出异常信息 ②退出程序

try-catch异常处理

1)Java提供try和catch块来处理异常,try块用于包含可能出错的代码,catch块yongyuchulitry块中发生的异常。可以根据需要在程序中有多个try-catch块;

2)基本语法

try{

    //可疑代码
    //将发生异常生成对应的异常对象,传递给catch块

}catch(异常){

    //对异常处理
    
}
//如果没有finally,语法上可以通过

try-catch处理异常的注意事项及细节

1)如果异常发生了,则异常后的代码不会执行,直接进入到catch块中;

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

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

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

5)可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。应用场景就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。

package com.pero.exception_;

/**
 * try-catch实践
 *
 * @author Pero
 * @version 1.0
 */

public class TryCatchDetail {
    public static void main(String[] args) throws Exception{


        //1)如果异常发生了,则异常后的代码不会执行,直接进入到catch块中;
        //2)如果异常没有发生,则顺序执行try的代码块,不会进入到catch块中;
        //3)如果希望不管是否发生异常,都执行某段代码块(比如关闭连接或者释放资源等等)则使用finally{ }块
        try {
            String str = "123456";
            int a = Integer.parseInt(str);  //如果此处有异常则后面的代码不再执行,直接进入catch块
            System.out.println("数字:" + a);
        } catch (NumberFormatException e) {
            System.out.println("异常信息:"+e.getMessage());
        }finally{
            System.out.println("finally代码块被执行");
        }
        System.out.println("程序继续执行");  //此处代码块继续执行

        //4)可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,
        //   比如(Exception在后,NullPointerException在前),如果发生异常值会匹配一个catch;
        try {
            Person person = new Person();
            person = null;
            System.out.println(person.getName());  //NullPointerException
            int n = 10;
            int m = 0;
            int res = n / m;  //ArithmeticException
        }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 {
            System.out.println("关闭相关资源");
        }

        //5)可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。
        //   应用场景就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。
        try {
            int i = 10;
            int j = 0;
            System.out.println(i/j);
        }finally {
            System.out.println("执行了finally");
        }
        System.out.println("程序继续执行");  //因为异常没有被捕获,程序直接退出,该行代码不会被执行
    }
}
class Person{
    private String name = "smith";

    public String getName() {
        return name;
    }
}

throws异常处理

1)如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应该显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理;

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

package com.pero.exception_;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * @author Pero
 * @version 1.0
 */
public class Throws01 {
    public static void main(String[] args) {

    }

    public void f1() throws FileNotFoundException,NullPointerException,
            ArithmeticException /*Exception*/{ 
        //3.显示地声明抛出异常,
        //  throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
        
        //4.throws 关键字后面也可以是异常列表,即可以抛出多个异常
        

        //创建一个文件流对象
        //这里的异常是一个FileNotFoundException 编译异常
        //1.可以使用try-catch-finally
        //2.可以使用throws,抛出异常,让调用f1方法的调用者处理异常
        FileInputStream fis = new FileInputStream("d://aa.txt");
    }
}

throws异常处理注意事项和使用细节

1)对于编译异常,程序中必须处理,使用try-catch或者throws

2)对于运行异常,程序中如果没有处理,默认就是throws的处理方式

3)子类重写父类方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出异常一致,要么为父类抛出异常的类型的子类型;

4)在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws。

package com.pero.exception_;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * throws处理异常的使用细节
 *
 * @author Pero
 * @version 1.0
 */
public class ThrowsDetail {
    public static void main(String[] args) throws ArithmeticException{  //异常默认处理方式,异常抛给JVM来处理
        //JVM直接抛出异常,并退出程序
        f2();
    }

    public static void f2() /*throws ArithmeticException*/{  //异常默认处理方式,异常抛给调用它的方法来处理
        //1)对于编译异常,程序中必须处理,使用try-catch或者throws
        //2)对于运行异常,程序中如果没有处理,默认就是throws的处理方式

        int i = 10;
        int j = 0;
        double res = i / j;
    }

    public static void f1() /*throws FileNotFoundException*/{
        //因为f3()方法抛出编译异常
        //这时要求f1()方法必须处理这个编译异常
        //使用try-catch-finally或者throws来处理异常

        try {
            f3();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } finally {

        }
    }

    public static void f4() /*throws ArithmeticException*/{
        //在f4()中调用f5()不报异常错误
        //因为f5()抛出的是运行异常,Java中不要求程序员显示处理,因为有默认处理机制
        f5();
    }

    public static void f5() throws ArithmeticException{  //这是一个运行异常

    }

    public static void f3() throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("d://aa.txt");
    }
}

class Father{
    public void method() throws RuntimeException{

    }
}

class Son extends Father{
    @Override
    public void method() throws RuntimeException/*NullPointerException*/ {
        //3)子类重写的方法,所抛出的异常类型要么和父类抛出异常一致,要么为父类抛出异常的类型的子类型;
        //4)在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws。
        super.method();
    }
}

自定义异常

基本概念

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

自定义异常的步骤

1)定义类:自定义异常类名继承Exception或RuntimeException;

2)如果继承Exception,属于编译异常;

3)如果继承RuntimeException,属于运行异常(一般来说继承RuntimeException)。

package com.pero.exception_;

/**
 * @author Pero
 * @version 1.0
 */
public class CustomException {
    public static void main(String[] args) throws AgeException{
        int age = 80;
        if (!(age >= 18 && age <= 120)){
            throw new AgeException("年龄需要在 18~120岁。");
        }else {
            System.out.println("你的年龄范围正确。");
        }
    }
}

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

throw和throws的区别

                        意义                                            位置                            后面跟的东西

throw    手动生成异常对象的关键词                方法体中                          异常对象

throws   异常处理的一种方式                        方法声明处                        异常类型

package com.pero.exception_;

/**
 * @author Pero
 * @version 1.0
 */
public class ReturnExceptionDemo {

    public static void main(String[] args) {
        try {
            ReturnExceptionDemo.methodA();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        ReturnExceptionDemo.methodB();
    }

    static void methodA(){
        try {
            System.out.println("进入方法A");
            throw new RuntimeException("制造异常");
        } finally {
            System.out.println("执行方法A中的finally");
        }
    }

    static void methodB(){
        try {
            System.out.println("进入方法B");
            return;
        } finally {
            System.out.println("执行方法B中的finally");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值