在计算机编程中,异常(Exception)是程序运行时出现的错误或意外情况。它们与一般的程序逻辑不同,可能会导致程序崩溃、数据损坏、内存泄漏等问题。
Java中的异常处理机制为程序员提供了一种可靠的方式来处理这些异常情况,并提供了标准化的异常类和函数调用方式,使得程序员可以更容易地诊断和debug程序。
当 Java 程序异常发生时,将生成一个异常对象。这个异常对象包含了异常类型和相关信息。Java 使用 try-catch
语句来捕获和处理异常。try
块中的代码可能会生成异常,而 catch
块中的代码则负责处理这些异常。
下面是一个简单的 Java 异常处理的示例:
try {
// 可能会发生异常的代码块
int result = 10 / 0;
} catch (ArithmeticException e) {
// 捕获并处理异常
System.out.println("除以零异常:" + e.getMessage());
}
上面的代码块尝试计算象征性的“10 ÷ 0”,这样的操作显然是非法的,会导致ArithmeticException
异常被抛出。在try
块中,我们通过使用除法操作符和数字字面量创建了这个异常。而在catch
块中,我们通过ArithmeticException
类型的参数来捕获这个异常,并输出异常信息。
Java还提供了一种finally
块,允许程序员放置一些不能被忽视的代码(比如资源释放),以根据是否发生异常进行特定的清理或报告操作。一个完整的异常处理过程通常看起来像这样:
try {
// 业务代码
} catch (SpecificException e) {
// 如果发生特定异常,做特定处理
} catch (AnotherException e) {
// 如果发生另外的异常,做特定处理
} finally {
// 不论是否有异常发生,都会执行该段代码
// 这里通常用于资源清理、关闭连接等操作
}
需要注意的是,在处理异常时,应该避免仅简单地打印错误信息或掩盖错误。正确的处理方式是将代码恢复到正常状态或报告错误给用户。 在某些情况下,异常还可以被收集和传递给上级调用者,以进一步处理。
除了像上面那样明确抛出的异常,Java中还有一类称为“检查异常”的异常。这种异常在编译时必须被捕获或声明被抛出,否则编译器将抛出编译时错误。
throw和throws的使用方法:
throw
和 throws
都是 Java 中处理异常的关键字,二者相似但含义不同。它们在语法上有很大区别,并且通常在不同的场景下使用。
throw
是一个关键字,用于在程序中显式抛出一个异常对象,使程序进入异常状态。通常情况下,throw
语句放置于方法体中,并用于检测代码中的错误条件。例如:
if (i < 0) {
throw new IllegalArgumentException("参数必须非负数");
}
这个示例代码中,一旦输入的参数 i
小于 0,就会自动触发异常并终止程序运行。
另外,通过 throw
我们也可以重新抛出捕获到的异常。比如:
try {
// 可能会抛出某种异常的代码块
} catch (SpecificException e) {
// 对异常进行特定处理
throw e; // 重新抛出该异常
}
这样可以使异常在当前方法中被捕获并处理,同时把整个异常链带到高层语境中。需要注意的是,如果我们已经对异常做了处理,那么在重新抛出它时请务必确认是否带有必要的更改。
throws
关键字用于声明方法可能抛出的所有异常类型,通常放置于方法定义上方。它指示编译器在方法中可能会有某些异常未被捕获,并提醒调用者使用 try-catch
语句来处理异常。例如:
public void method() throws SpecificException, AnotherException {
// 可能会抛出上述两种异常的代码块
}
在这个示例中,我们定义了一个 method()
方法,并在方法声明上方添加了 throws
关键字。这表明该方法可能会抛出两种类型的异常,而且调用者必须采取适当措施处理它们。
需要注意的是,如果我们忘记在方法上定义 throws
关键字,Java 编译器会输出错误信息,并提示我们必须捕获或定义可能抛出的异常。因此,在编写自己的 Java 方法时,我们应该仔细考虑哪些异常对于调用代码而言是可重要的。
总的来说,throw
用于抛出单个异常,而 throws
声明方法可能抛出多个异常。它们都是 Java 中处理异常的关键组成项。
常见的异常类型
异常类型 | 描述 |
---|---|
ArithmeticException | 指在数学计算过程中出现异常,例如除数为 0。 |
ArrayIndexOutOfBoundsException | 数组或 ArrayList 索引越界。 |
ClassCastException | 在强制类型转换期间尝试将对象转换为不兼容的类型。 |
IllegalArgumentException | 提供了非法参数。 |
NullPointerException | 尝试访问 null 对象或为空的对象。 |
NumberFormatException | 字符串转数字时,字符串无效或格式不正确 |
FileNotFoundException | 文件路径或名称错误。 |
IOException | 当发生 I/O 输入输出方面的问题时抛出该异常,例如文件读写、网络 HTTP 请求等。 |
InterruptedException | 当线程正在休眠、等待时间,或被中断时抛出该异常 |
NoSuchMethodException | 调用的方法不存在于类定义中的异常。 |
SecurityException | 安全管理器通知是否可以访问资源时抛出。 |
UnsupportedOperationException | 操作不受支持或未实现的异常。 |
throw new exception手动抛出异常
在 Java 中,throw new Exception()
语句用于手动抛出一个异常。通常情况下,我们使用这个语句来表示代码执行过程中遇到了无法继续执行的问题,需要将这个问题传递(或者说抛出)给上层调用者或者异常处理机制进行处理。
例如,以下是一个简单的程序,演示了如何通过 throw new Exception()
语句手动抛出一个运行时异常:
public class Main {
public static void main(String[] args) {
try {
int result = divide(10, 0);
System.out.println("result = " + result);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static int divide(int dividend, int divisor) throws Exception {
if (divisor == 0) {
throw new Exception("除数不能为0");
}
return dividend / divisor;
}
}
在这个程序中,我们定义了一个带有两个参数的 divide
方法,它会计算两个整数相除的结果。如果除数为 0,就会手动抛出一个新的 Exception 异常,并将异常消息设置为 “除数不能为0”。
在主程序中,我们调用这个 divide 方法,并在 try-catch 块中捕获可能抛出的异常。因为该方法声明了 throws Exception
异常,所以在调用该方法时也需要进行异常处理。
当程序运行并执行到 divide(10, 0)
这一行代码时,会检测到除数为 0 的错误情况,并抛出一个带有异常信息的新 Exception 异常。该异常被传递到上层调用者(即 main 方法),并由 catch 块处理打印输出。
总之,throw new Exception()
可以让我们手动抛出一个异常并将其传递给相应的异常处理机制进行处理。在实际开发中,我们经常使用这种语句来表示代码执行过程中可能出现的问题,提供更精细、更详尽的程序错误信息。
自定义异常类型
在 Java 中,我们可以通过继承 Exception 或 RuntimeException 类来创建自定义异常类型。
- 继承 Exception 类创建受检查异常
public class MyCheckedException extends Exception {
// 构造函数
public MyCheckedException() {
super();
}
public MyCheckedException(String message) {
super(message);
}
}
在上述代码中,我们定义了一个名为 MyCheckedException
的受检查异常,这是通过继承 Exception 类来实现的。该类有两个构造函数,第一个是无参构造函数,第二个是带有消息参数的构造函数。这个自定义异常会在程序编译时强制要求处理该异常。
- 继承 RuntimeException 类创建运行时异常
public class MyRuntimeException extends RuntimeException {
// 构造函数
public MyRuntimeException() {
super();
}
public MyRuntimeException(String message) {
super(message);
}
}
上述代码是继承 RuntimeException 类实现的自定义异常,它是非受检查异常,不需要显式捕获或处理。此类异常通常由程序员编写的代码逻辑错误导致,且可以在运行时重新抛出。
使用自定义异常:
public class MyService {
public void doSomething(int x) throws MyCheckedException, MyRuntimeException {
if (x < 0) {
throw new MyCheckedException("参数不能小于 0");
} else if (x == 0) {
throw new MyRuntimeException("参数不能等于 0");
} else {
// ...
}
}
}
上述代码中,我们在 doSomething
方法中使用了自定义异常。当传入的参数 x
小于 0 时,会抛出受检查异常 MyCheckedException
;当传入的参数为 0 时,会抛出非受检查异常 MyRuntimeException
。调用该方法时,需要显式声明方法可能会抛出的异常类型。
总之,在需要特定场景或规则的异常处理时,可通过自定义异常类型实现抛出、捕获、处理等操作,从而提高程序的健壮性和安全性。