Java API:3. Throwable

1. 异常的介绍

在编程中,异常错误是两种重要的运行时问题,它们代表了程序在执行过程中出现的异常情况。理解它们的区别和如何处理异常是编写健壮程序的基础。

1.1 错误(Error)

**错误(Error)**表示一些严重的、通常无法恢复的程序问题。错误通常是由于虚拟机(JVM)等底层环境的内部故障引起的,程序员无法捕捉或处理这些错误。

错误的特点:

  • 不常见:错误通常发生在程序执行的基础环境中,应用程序本身无法直接引起。
  • 无法解决:一旦出现错误,程序通常无法继续执行。解决错误通常意味着修改系统配置或更换硬件,而非通过代码修改。
  • 尽量避免:错误通常不可预见且无法避免,所以在实际开发中我们尽量避免会导致错误的操作或环境配置问题。

常见的错误示例:

  • OutOfMemoryError:表示JVM内存不足,无法分配内存。
  • StackOverflowError:表示程序调用栈溢出,通常是由于递归调用过深造成的。
// OutOfMemoryError示例
public class ErrorExample {
    public static void main(String[] args) {
        // 大量分配内存,模拟内存溢出错误
        try {
            int[] arr = new int[Integer.MAX_VALUE];
        } catch (Error e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
1.2 异常(Exception)

**异常(Exception)**表示程序在执行时出现的意外情况,可以通过代码捕捉并进行处理。异常是程序可以预见并且通过适当的手段进行修复的。

异常的特点:

  • 常见:异常发生的频率要远高于错误,通常是由于程序中的输入错误、资源不可用、网络中断等原因造成的。
  • 可解决:与错误不同,异常可以通过捕捉和处理来解决。例如,捕获网络连接失败异常并重新尝试连接,或者捕获用户输入错误并提示用户重新输入。
  • 代码语法无问题:当程序发生异常时,通常是运行时出现的问题,而不是代码语法错误。

异常的分类:

  1. 检查型异常(Checked Exception):这类异常是编译器强制要求进行处理的。如果方法中可能抛出某种检查型异常,必须通过try-catch语句或throws声明来处理或传递该异常。常见的检查型异常有IOExceptionSQLException等。
  2. 非检查型异常(Unchecked Exception):这类异常在编译时不要求进行处理,它们通常是程序的逻辑错误,发生时无法预见到。非检查型异常的根类是RuntimeException。常见的非检查型异常有NullPointerExceptionArrayIndexOutOfBoundsExceptionArithmeticException等。
// 处理异常示例
public class ExceptionExample {
    public static void main(String[] args) {
        try {
            // 假设除以0抛出异常
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            System.out.println("异常: " + e.getMessage());
        } finally {
            System.out.println("无论是否发生异常,finally块都会执行");
        }
    }
}

总结:

  • 错误通常是由系统环境问题引起,无法通过代码解决,程序员无法捕获或处理它们。
  • 异常则是程序中常见的问题,可以通过捕捉和处理来使程序继续运行,代码通常会明确声明哪些异常可能发生,并做好处理。

异常处理机制是Java中处理程序运行时问题的核心,学习如何有效地捕捉和处理异常是开发稳定程序的重要步骤。


2. 异常举例以及解决常见错误bug方案

在程序开发中,我们难免会遇到一些错误和异常,尤其是在编写复杂功能时。学习如何定位错误、理解异常信息、以及如何解决常见的错误,对于提高调试和问题解决的效率至关重要。

2.1 定位错误

定位错误时,最重要的是理解异常提示信息。Java的异常信息通常会提供足够的细节来帮助我们定位问题。异常信息包括错误类型、错误发生的位置(代码行号)、以及堆栈跟踪。

步骤:

  1. 运行程序,查看控制台中出现的异常提示。
  2. 异常信息会提供错误的类型(如ArithmeticExceptionArrayIndexOutOfBoundsException)以及发生错误的代码行。
  3. 如果异常信息足够明确,可以直接根据错误提示修改代码。
  4. 如果不理解异常信息,可以搜索错误类型,通常可以在StackOverflow或者Java文档中找到相关解决方案。
2.2 常见错误及解决方案

在以下代码示例中,我们可以看到两种常见的错误,并提供了如何通过异常信息定位和解决这些错误的方法。

package com.nix.demo;

import org.junit.Test;

// 2. 异常举例以及解决常见错误bug方案
// 定位错误:编写好程序后,运行程序,在输入运行结果栏中会存在异常提示,红色中蓝色链接,就能找到自己的代码错误
//解决错误:先阅读异常提示,如果了解就直接修改,如果不了解那就搜索异常提示,了解问题所在,解决问题
public class Main {
    @Test
    public void demo() {
        // ArithmeticException: / by zero (除数为零)
        System.out.println(1 / 0);  // 此处会抛出异常:ArithmeticException
    }

    @Test
    public void demo2() {
        int[] a = {1, 2, 3, 4};
        // ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 4 (索引越界)
        System.out.println(a[5]);  // 此处会抛出异常:ArrayIndexOutOfBoundsException
    }
}

2.3 错误举例

  1. 除零异常 (ArithmeticException)

    public void demo() {
        System.out.println(1 / 0);
    }
    

    异常信息:

    java.lang.ArithmeticException: / by zero
    

    解决方案:

    • 这是由于尝试将一个数除以0导致的错误。解决方法是检查除数是否为0,并在除法操作前进行适当的验证。
    public void demo() {
        int divisor = 0;
        if (divisor != 0) {
            System.out.println(1 / divisor);
        } else {
            System.out.println("除数不能为零");
        }
    }
    
  2. 数组越界异常 (ArrayIndexOutOfBoundsException)

    public void demo2() {
        int[] a = {1, 2, 3, 4};
        System.out.println(a[5]);
    }
    

    异常信息:

    java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 4
    

    解决方案:

    • 这表示你尝试访问数组中不存在的索引。数组a的长度为4,而你尝试访问索引5。解决方法是检查数组的长度并确保索引在有效范围内。
    public void demo2() {
        int[] a = {1, 2, 3, 4};
        int index = 5;
        if (index < a.length) {
            System.out.println(a[index]);
        } else {
            System.out.println("数组索引越界");
        }
    }
    

2.4 处理异常

为了提高程序的健壮性,避免程序崩溃,可以使用try-catch语句来捕捉并处理异常。

例如,对于除零异常,我们可以使用try-catch块来捕捉并处理:

public void demo() {
    try {
        System.out.println(1 / 0);
    } catch (ArithmeticException e) {
        System.out.println("捕获到异常: " + e.getMessage());
    }
}

对于数组越界异常,我们也可以用类似的方式处理:

public void demo2() {
    int[] a = {1, 2, 3, 4};
    try {
        System.out.println(a[5]);
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("数组索引越界: " + e.getMessage());
    }
}

总结

  • 定位错误:阅读异常提示,定位错误发生的位置。错误信息中通常会包含错误类型、行号和堆栈信息,帮助我们理解问题。
  • 解决错误:根据异常信息判断问题所在,并采取措施解决。常见的错误如除零异常和数组越界异常,可以通过添加检查逻辑来解决。
  • 异常处理:使用try-catch语句捕捉异常,避免程序崩溃,并提供用户友好的错误信息。

3. RuntimeException 解析

在 Java 中,异常被划分为两大类:运行时异常(RuntimeException)**和**非运行时异常(checked exceptions)。这两类异常的处理方式和影响有所不同,下面我们将详细分析 RuntimeException 以及它与非运行时异常的区别。

3.1 运行时异常(RuntimeException)

RuntimeException 属于 未检查异常(Unchecked Exception),在编译时,Java 不强制要求捕获这种类型的异常。也就是说,程序员可以选择是否在代码中捕获这种异常。

特点:

  • 不会强制要求捕获:编译器不会强制要求我们用 try-catch 或者 throws 来处理 RuntimeException,因为它是一个运行时异常。
  • 不影响项目运行:虽然 RuntimeException 会导致程序在某个时刻出现问题,但它不会影响程序的编译和执行过程,通常是逻辑错误或者不符合预期的运行状态。
  • 程序员可以修改或不修改RuntimeException 不必在代码中处理,但如果有可能会触发这种异常,最好进行防范处理。

常见的 RuntimeException 类型包括:

  • ArithmeticException(如除以零)
  • NullPointerException(空指针异常)
  • IndexOutOfBoundsException(数组或列表索引越界)
  • IllegalArgumentException(非法参数异常)
3.2 非运行时异常(Checked Exception)

RuntimeException 不同,非运行时异常是需要进行处理的,Java 强制要求捕获或者声明(通过 throws)这种异常。

特点:

  • 必须处理:非运行时异常会强制要求你进行捕获(try-catch)或者声明(throws)。
  • 影响程序执行:这种异常通常会导致程序无法继续执行,必须进行合理的异常处理,或者通过预防措施避免出现异常。

常见的非运行时异常:

  • IOException(输入输出异常)
  • SQLException(SQL 异常)
  • FileNotFoundException(文件未找到异常)
3.3 代码示例

以下是一些常见的 RuntimeException 示例:

package com.nix.demo;

import org.junit.Test;

// 3. RuntimeException
/*
  异常类有两个主要的子类:IOException 类和 RuntimeException 类

1.运行时异常 RuntimeException
   运行时异常可修改也可不修改,不会对项目运行产生影响
   运行时异常像游戏漏洞,它不影响我们玩游戏,但是我们有一些漏洞可以捡,比如更新以后某个英雄的技能,在某个时间可以无限的放或者平A就能秒死人

2.非运行时异常
   非运行时异常必须修改,因为这样会使得项目直接无法运行(现在的编译器比较智能,一定会让你try catch) 
   但是非运行时异常导致你进不去游戏
   编译器中,运行时异常不会要求你捕获,但是非运行时异常会强制要求你捕获,所以我们在编写自定义异常的
    时候不会定成运行时异常
 */
public class Main {
    @Test
    public void demo1() {
        // 运行时异常: 除零异常
        System.out.println(1 / 0);  // 会抛出 ArithmeticException
    }

    @Test
    public void demo2() {
        try {
            // 运行时异常: 类未找到
            Class.forName("test321.hello");  // 会抛出 ClassNotFoundException
        } catch (ClassNotFoundException e) {
            System.out.println("ClassNotFoundException: " + e.getMessage());
        }
    }
}
3.4 异常说明
  1. demo1 示例

    System.out.println(1 / 0);
    

    该代码会抛出一个 ArithmeticException,因为除以零在数学上是没有定义的,因此 Java 会抛出一个运行时异常 ArithmeticException。这是一种运行时异常,程序可以选择不处理,但最好加以预防。

  2. demo2 示例

    Class.forName("test321.hello");
    

    该代码会抛出一个 ClassNotFoundException,因为指定的类 test321.hello 并不存在。ClassNotFoundException 是一个检查型异常,Java 编译器会强制要求你捕获它或声明抛出该异常。尽管 ClassNotFoundException 不是 RuntimeException,它依然需要处理。

3.5 运行时异常的处理

虽然 RuntimeException 不需要强制捕获,但在实际开发中,我们通常会根据需求对运行时异常进行适当的处理。例如:

  • 在输入数据时检查有效性,避免空指针异常。
  • 在除法运算中检查除数是否为零,避免算术异常。
  • 在访问数组或列表时检查索引是否越界。

示例: 处理 ArithmeticExceptionNullPointerException

public void safeDivide(int a, int b) {
    try {
        if (b == 0) {
            System.out.println("除数不能为零");
        } else {
            System.out.println(a / b);
        }
    } catch (ArithmeticException e) {
        System.out.println("发生除零错误");
    }
}

public void safeAccessArray(int[] arr, int index) {
    try {
        System.out.println(arr[index]);
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("数组索引越界");
    }
}

3.6 总结

  • 运行时异常(RuntimeException:无需强制处理,可以选择捕获或不捕获,但应在可能发生异常的地方加入预防措施。
  • 非运行时异常(Checked Exception):需要强制捕获或声明,程序员必须处理这些异常,否则编译无法通过。
  • 通过合理的异常处理和预防措施,我们能够提高程序的健壮性,避免程序崩溃。

4. try-catch 异常捕获与处理

在 Java 中,try-catch 语句是用于捕获并处理异常的一种方式。它可以帮助我们有效地管理程序中可能出现的错误或异常情况,确保程序能够继续执行,而不会因为错误导致整个应用崩溃。

4.1 try-catch 语句的基本结构

try-catch 语句的基本语法如下:

try {
    // 可能抛出异常的代码块
} catch (ExceptionType1 e1) {
    // 捕获并处理ExceptionType1类型的异常
} catch (ExceptionType2 e2) {
    // 捕获并处理ExceptionType2类型的异常
} finally {
    // 最终执行的代码块,无论是否发生异常都会执行
}
  • try:在 try 块中写可能会抛出异常的代码。如果代码中发生了异常,控制权就会转到后续的 catch 块。
  • catch:用来捕获并处理指定类型的异常。如果 try 块中的代码抛出了该类型的异常,那么相应的 catch 块就会执行。
  • finallyfinally 块中的代码无论是否发生异常都会执行。它通常用于释放资源(如关闭文件流、数据库连接等)。
4.2 代码示例与解释

在下面的例子中,我们使用 try-catch 语句捕获 ArrayIndexOutOfBoundsException 异常,并在 finally 块中输出“异常捕获完成!”:

package com.nix.demo;

import org.junit.Test;

public class Main {
    @Test
    public void demo() {
        // 在try块中,程序会执行代码,如果出现异常,它会跳到对应的catch块来处理。
        try {
            int[] a = new int[2];  // 创建长度为2的数组
            System.out.println("Access element three :" + a[3]);  // 尝试访问超出数组范围的元素

            System.out.println("Out of the block");
        } catch (Exception e) {
            // 捕获并处理异常
            // 可以选择输出异常信息,方便调试
            // e.printStackTrace();
            System.out.println("index越界!");
        } finally {
            // finally 块中的代码总会执行
            System.out.println("异常捕获完成!");
        }
    }
}
4.3 运行结果

当程序执行时,首先会进入 try 块,尝试访问数组 a[3]。由于数组的最大索引为 1,a[3] 会引发 ArrayIndexOutOfBoundsException 异常。异常被 catch 块捕获并输出 "index越界!",然后程序执行 finally 块,输出 "异常捕获完成!"

输出:

index越界!
异常捕获完成!
4.4 finally 的作用
  • 确保执行:无论 try 块中是否发生异常,finally 中的代码总是会被执行。这对于需要关闭资源(如文件流、数据库连接等)非常有用。
  • 强制执行:即使 try-catch 语句块内发生了 return 语句,finally 块的代码仍然会执行。
4.5 注意事项
  1. finally 块的执行顺序:即使 try 块内出现了 return 语句,finally 块的代码也会在返回前执行。因此,finally 常用于关闭资源,如文件流、数据库连接等。
  2. 滥用 try-catch:虽然 try-catch 可以帮助我们捕获异常,但也不能滥用。在一些情况下,我们不应该忽略异常或捕获所有异常,而是应该尽量通过正确的设计来避免异常的发生。
  3. 异常的处理策略:在一些情况下,catch 块只输出异常信息而不处理异常,这对于调试非常有用,但在生产环境中,应当根据实际需求进行处理或重抛异常。
4.6 不建议在生产代码中“骗毕业设计”

根据上面的例子,我们可以看到 try-catch 能有效捕获异常并继续执行程序。然而,在实际工作中,我们不应该随意捕获异常而不做任何处理,这可能会掩盖程序中的潜在问题。

例如,以下代码:

try {
    // 一些可能抛出异常的代码
} catch (Exception e) {
    // 忽略异常,不做任何处理
    // 这种做法是不推荐的
}

这种做法虽然在短期内不会导致程序崩溃,但会让程序隐瞒错误,给未来的调试和维护带来困难。因此,应该尽量确保异常有明确的处理方式或在必要时进行日志记录。

4.7 总结
  • try-catch 是 Java 中处理异常的主要方式,通过它可以捕获并处理运行时异常。
  • finally 块用于确保一定会执行的代码,通常用于资源释放等清理操作。
  • 不要滥用 try-catch,尽量避免捕获所有异常而不做处理,要根据业务需求合理捕获并处理异常。

5. NullPointerException 空指针异常

NullPointerException(空指针异常)是 Java 中常见的一种运行时异常。它通常在程序试图访问一个尚未初始化(即值为 null)的对象或调用一个 null 引用的实例方法时发生。

5.1 常见引发空指针异常的场景

空指针异常通常发生在以下几种情况下:

  1. 调用空对象的实例方法:在 null 对象上调用方法时,会抛出空指针异常。

    String str = null;
    int length = str.length();  // 这里会抛出 NullPointerException
    
  2. 访问或修改 null 对象的字段:如果你尝试访问或修改一个值为 null 的对象字段,也会发生空指针异常。

    MyClass obj = null;
    int value = obj.someField;  // 会抛出 NullPointerException
    
  3. null 当作数组进行操作:如果尝试对一个 null 引用当作数组来进行操作,比如访问数组的元素或获取数组长度,也会抛出空指针异常。

    int[] arr = null;
    int len = arr.length;  // 这里会抛出 NullPointerException
    
  4. null 作为 Throwable 值抛出:如果尝试将 null 抛出作为异常,也会导致空指针异常。

    throw null;  // 会抛出 NullPointerException
    
5.2 代码示例

在下面的代码示例中,我们故意引发空指针异常,通过访问一个值为 null 的数组元素来展示这一行为。

package com.nix.demo;

import org.junit.Test;

public class DemoTest {
    @Test
    public void demo() {
        int[] a = null;  // 将数组设置为null

        // 尝试访问空数组的元素,导致 NullPointerException
        System.out.println(a[1]);  // 会抛出 NullPointerException
    }
}
5.3 运行结果

当程序执行时,它会尝试访问数组 a 的元素,但由于 anull,访问 a[1] 时会抛出 NullPointerException,输出如下:

Exception in thread "main" java.lang.NullPointerException: Cannot load from int array because "a" is null
    at com.nix.demo.DemoTest.demo(DemoTest.java:10)
5.4 解决空指针异常的方法

为了避免空指针异常,可以采取以下几种方式:

  1. 检查是否为 null:在访问对象或数组之前,可以通过 if 语句检查对象是否为 null

    if (a != null) {
        System.out.println(a[1]);
    } else {
        System.out.println("数组a为null");
    }
    
  2. 使用 Optional:Java 8 引入了 Optional 类,它可以帮助你避免直接操作 null 值。通过 Optional 可以更安全地处理可能为 null 的值。

    Optional<String> str = Optional.ofNullable(null);
    System.out.println(str.orElse("默认值"));
    
  3. 使用注解:一些工具(如 @NotNull, @Nullable)可以帮助你标明哪些变量不应该为 null,这有助于提高代码的可读性和安全性。

  4. 初始化对象:在声明对象时尽量初始化,避免后续使用时为 null

    String str = "";
    
5.5 小结
  • NullPointerException 是由于对 null 引用执行不允许的操作(如调用方法、访问字段、数组操作等)时抛出的异常。
  • 为了避免空指针异常,程序员应确保在使用对象前进行 null 检查,并采取适当的异常处理措施。
  • 在实际编程中,null 应该尽量避免使用,特别是当能通过其他方式避免 null 的出现时。

6. throws 的使用

在 Java 中,throws 是用于声明方法可能抛出的异常的关键字。它通常与 throw 关键字一起使用,throw 用于实际抛出异常,而 throws 用于在方法声明中指定该方法可能抛出的异常类型。使用 throws 可以让调用者知道该方法可能会发生异常,从而采取适当的处理措施。

6.1 throwthrows 的区别
  • throw:用于在方法体内抛出异常,表示程序运行过程中某个条件触发时需要手动抛出异常。

    throw new FileNotFoundException("文件未找到!");
    
  • throws:用于在方法声明中指定该方法可能会抛出的异常类型,告知调用该方法的代码,可能会遇到该异常。throws 通常用于方法签名中。

    public void demo1() throws FileNotFoundException {
        // 可能会抛出异常
    }
    
6.2 throws 的作用

throws 关键字并不处理异常,它仅仅是声明一个方法可能抛出某种类型的异常。这样做有助于:

  • 让调用该方法的代码提前知晓可能会遇到的异常,从而可以适当地进行异常处理。
  • 使得代码在出现异常时,能够清晰地知道是哪一段代码引起了问题。
6.3 示例代码

在以下代码中,我们演示了 throws 的使用,抛出了 FileNotFoundException 异常,表示文件未找到时,应该抛出异常:

package com.nix.demo;

import org.junit.Test;

import java.io.FileNotFoundException;

public class DemoTest {
    @Test
    public void demo1() throws FileNotFoundException {
        // 模拟文件是否存在的判断
        boolean fileExists = false;  // 假设文件不存在

        if (!fileExists) {
            throw new FileNotFoundException("文件不存在!");
        }
    }
}
6.4 运行结果

当程序执行时,如果 fileExistsfalse,将会抛出 FileNotFoundException,输出类似以下内容:

Exception in thread "main" java.io.FileNotFoundException: 文件不存在!
    at com.nix.demo.DemoTest.demo1(DemoTest.java:10)
    at com.nix.demo.DemoTest.demo1(DemoTest.java:9)
6.5 异常声明

如果方法可能抛出某种异常,则需要在方法签名中使用 throws 来声明该异常。例如,如果某个方法可能会抛出 IOExceptionFileNotFoundException,你需要在方法签名中使用 throws 声明:

public void readFile(String fileName) throws FileNotFoundException, IOException {
    // 代码逻辑
}
6.6 小结
  • throw 用于抛出异常,是在方法体内进行操作。
  • throws 用于声明一个方法可能会抛出异常,是在方法声明中进行声明。
  • 使用 throws 可以让方法的调用者知道可能会抛出哪些异常,从而进行适当的异常处理。

在实际开发中,throwsthrow 是异常处理机制的重要组成部分,合理使用可以提高代码的可维护性和健壮性。


7. 通过调用函数的形式抛出异常

在 Java 中,我们不仅可以通过手动 throw 异常,还可以通过调用方法来抛出异常。通过在方法签名中声明 throws 来指明该方法可能会抛出某种异常,然后在方法体内根据条件进行异常的抛出。这样可以确保调用方法时,调用者能够清晰地看到可能出现的异常,并进行适当的异常处理。

7.1 自定义异常

在示例中,我们定义了一个名为 MyException 的自定义异常类,继承自 Exception,并在方法 sum() 中检查输入条件,如果不符合要求则抛出 MyException 异常。

package com.nix.demo;

public class MyException extends Exception {
    public MyException(String message) {
        super(message);  // 调用父类构造函数,传递错误消息
    }
}

自定义异常类继承 Exception,这样它就成为一个受检异常(Checked Exception),需要通过 throws 声明在方法签名中。

7.2 示例代码解析

在这个例子中,sum() 方法用于计算两个数字的和,但只有在两个数字都在 0 到 10 之间时才能执行。如果任一数字不符合条件,就会抛出 MyException 异常。

package com.nix.demo;

import org.junit.Test;

public class DemoTest2 {

    // 进行加法计算,并在不符合要求时抛出异常
    public int sum(int a, int b) throws MyException {
        // 如果参数不在规定范围内,则抛出自定义异常
        if (a > 10 || b > 10 || a < 0 || b < 0) {
            throw new MyException("只能求10以内的加法");
        }
        return a + b;
    }

    @Test
    public void demo() {
        try {
            // 调用sum方法,传入不符合条件的参数
            int number = sum(100, 200);
        } catch (MyException e) {
            // 捕获并处理异常
            e.printStackTrace();
        }
    }
}
7.3 代码执行

sum() 方法中,我们检查输入的数字。如果任一数字超出范围(即大于 10 或小于 0),我们通过 throw new MyException("错误信息") 抛出一个自定义的异常。

// 当参数为 (100, 200) 时,会抛出 MyException 异常
throw new MyException("只能求10以内的加法");

demo() 方法通过 try-catch 语句捕获并打印异常信息。异常被捕获后,e.printStackTrace() 会输出异常堆栈跟踪信息,帮助开发者了解异常发生的位置和原因。

7.4 运行结果

当我们执行 demo() 方法时,传入的数字 100200 超出了合法范围,导致抛出 MyException 异常。输出的异常信息如下:

com.nix.demo.MyException: 只能求10以内的加法
    at com.nix.demo.DemoTest2.sum(DemoTest2.java:6)
    at com.nix.demo.DemoTest2.demo(DemoTest2.java:14)
7.5 异常的好处
  1. 自定义异常:通过自定义异常 MyException,可以明确区分不同类型的错误,有助于代码的可读性和维护性。
  2. 方法签名的声明sum() 方法通过 throws 声明可能会抛出异常,调用者在调用该方法时必须处理异常(使用 try-catchthrows)。
  3. 异常处理try-catch 语句捕获并处理异常,避免程序崩溃或错误的扩展到其他地方。
7.6 小结

通过调用函数的方式抛出异常,结合自定义异常和 throws 机制,可以有效地将异常处理逻辑从主业务逻辑中分离,增强代码的可维护性。在实际开发中,遇到不合法的输入或执行状态时,可以通过抛出异常来通知调用者进行必要的处理。


8. 手把手教你编写自定义异常

在这个例子中,我们展示了如何创建一个自定义异常 NixException,并通过枚举类 NixCodeEnum 来管理不同的错误码和错误信息。

我们将异常类、枚举类和接口整合到一起,形成了一个结构清晰、可维护的异常处理方案。这个方案的好处是可以通过错误码统一管理不同类型的异常,从而让异常处理更加规范化和一致化。

8.1 自定义错误码接口 ErrorCode

首先,定义了一个 ErrorCode 接口,该接口规定了获取错误码和错误信息的方法。每个错误码类都需要实现这个接口,以确保每个错误都能够获取到统一的错误码和错误信息。

package com.nix.demo;

public interface ErrorCode {
    /**
     * 获取错误码
     * @return 错误码
     */
    String getCode();

    /**
     * 获取错误信息
     * @return 错误信息
     */
    String getMessage();
}
8.2 创建枚举类 NixCodeEnum

接下来,我们创建了一个枚举类 NixCodeEnum,用于存储具体的错误码和错误信息。每一个枚举值代表一种错误类型,它包括了错误码(code)和错误信息(msg)。通过 getCode()getMessage() 方法,我们可以在代码中获取相应的错误码和错误信息。

package com.nix.demo;

public enum NixCodeEnum implements ErrorCode {
    NOT_FOUND_PAGE("404", "找不到网站资源"),
    NOT_FOUND_FILE("888", "找不到文件"),
    NOT_O_TEN("bad", "只能求10以内的加法");

    private final String code;
    private final String msg;

    NixCodeEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    @Override
    public String getCode() {
        return code;
    }

    @Override
    public String getMessage() {
        return msg;
    }
}

通过枚举类,我们不仅可以定义多个错误码,还可以为每个错误码配备具体的错误信息。这样,当出现异常时,我们可以通过枚举类提供的错误码和错误信息来描述问题。

8.3 自定义异常类 NixException

接下来,定义自定义异常类 NixException,继承自 RuntimeException。构造方法接收 ErrorCode 类型的参数,将错误信息传递给 RuntimeException 的构造函数。

package com.nix.demo;

public class NixException extends RuntimeException {
    public NixException(ErrorCode errorCode) {
        super(errorCode.getMessage());
    }
}

这里的 NixException 继承了 RuntimeException,意味着它是一个运行时异常。异常信息来自于传入的 ErrorCode 对象,它会通过构造函数的 super() 方法传递给 RuntimeException

8.4 使用自定义异常

最后,在 sum 方法中使用自定义异常。当传入的参数不满足要求时,抛出 NixException 异常,并通过枚举 NixCodeEnum 中的 NOT_O_TEN 错误码来描述这个错误。

package com.nix.demo;

import org.junit.Test;

public class DemoTest {
    public int sum(int a, int b) throws NixException {
        // 如果参数超出范围,则抛出自定义异常
        if (a > 10 || b > 10 || a < 0 || b < 0) {
            throw new NixException(NixCodeEnum.NOT_O_TEN);
        }
        return a + b;
    }

    @Test
    public void demo() {
        try {
            int number = sum(100, 200);
        } catch (NixException e) {
            // 捕获并打印异常信息
            e.printStackTrace();
        }
    }
}
8.5 代码执行

sum() 方法中,我们检查输入的数字是否超出范围,如果超出则抛出 NixException 异常。异常通过 NixCodeEnum.NOT_O_TEN 传递错误码和错误信息。

运行 demo() 方法时,传入的数字 100200 不满足要求,因此抛出 NixException 异常。异常信息通过 e.printStackTrace() 打印出来,输出如下:

com.nix.demo.NixException: 只能求10以内的加法
    at com.nix.demo.DemoTest.sum(DemoTest.java:6)
    at com.nix.demo.DemoTest.demo(DemoTest.java:14)
8.6 总结

通过自定义异常和错误码,我们能够灵活地管理不同类型的错误,并提供详细的错误信息。通过枚举类来组织错误码,异常类可以更加规范、易于维护。这种方法非常适用于需要统一处理多种类型错误的应用场景。

优势
  • 清晰的错误处理:通过枚举类 NixCodeEnum 管理错误码,使得错误的定义和管理更清晰。
  • 可扩展性:可以轻松添加更多的错误码和错误信息,而不需要修改异常类。
  • 统一的异常处理:自定义异常 NixException 使得异常捕获和处理更加一致和易于维护。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值