- Java教程
- Java - 主页
- Java - 概述
- Java - 环境设置
- Java - 基本语法
- Java - 变量类型
- Java - 基本数据类型
- Java - 基本运算符
- Java 控制语句
- Java - 循环控制
- Java - 决策
- Java - 如果-否则
- Java-开关
- Java - For 循环
- Java - For-Each 循环
- Java - While 循环
- Java - do-while 循环
- Java - 中断
- Java - 继续
- 面向对象编程
- Java - 对象和类
- Java - 方法
- Java - 构造函数
- Java - 访问修饰符
- Java-继承
- Java-多态性
- Java - 重写
- Java-抽象
- Java-封装
- Java - 接口
- Java - 包
- Java - 内部类
- Java 数据类型
- Java - 字符
- Java 文件处理
- Java - 文件和 I/O
- Java 错误与异常
- Java - 异常
- Java多线程
- Java-多线程
- Java同步
- Java-同步
- Java-线程间通信
- Java-线程死锁
- Java-线程控制
- Java网络
- Java-网络
- Java-URL 处理
- Java - 泛型
- Java集合
- Java - 集合
- Java列表接口
- Java - 列表接口
- Java队列接口
- Java - 队列接口
- Java地图接口
- Java - 地图接口
- Java - SortedMap 接口
- Java设置接口
- Java - 设置接口
- Java - SortedSet 接口
- Java数据结构
- Java - 数据结构
- Java-枚举
- Java 集合算法
- Java - 集合
- Java - 迭代器
- Java - 比较器
- Java杂项
- Java - 正则表达式
- Java-序列化
- Java - 发送电子邮件
- Java - Applet 基础知识
- Java - 文档
- Java 有用资源
- Java - 问题与解答
- Java - 快速指南
- Java - 有用的资源
- Java - 讨论
- Java - 示例
Java - 异常
异常(或异常事件)是程序执行过程中出现的问题。当异常发生时,程序的正常流程被打乱,程序/应用程序异常终止,这是不推荐的,因此,需要对这些异常进行处理。
异常的发生可能有多种原因。以下是一些发生异常的场景。
用户输入了无效数据。
找不到需要打开的文件。
网络连接在通信过程中丢失或 JVM 内存不足。
其中一些异常是由用户错误引起的,另一些是由程序员错误引起的,还有一些是由以某种方式发生故障的物理资源引起的。
基于这些,我们将异常分为三类。您需要了解它们才能了解 Java 中异常处理的工作原理。
检查异常- 检查异常是编译器在编译时检查(通知)的异常,也称为编译时异常。这些异常不能简单地被忽略,程序员应该照顾(处理)这些异常。
例如,如果在程序中使用FileReader类从文件中读取数据,如果其构造函数中指定的文件不存在,则会出现FileNotFoundException,编译器会提示程序员处理该异常。
例子
import java.io.File; import java.io.FileReader; public class FilenotFound_Demo { public static void main(String args[]) { File file = new File("E://file.txt"); FileReader fr = new FileReader(file); } }
如果您尝试编译上述程序,您将得到以下异常。
输出
C:\>javac FilenotFound_Demo.java FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown FileReader fr = new FileReader(file); ^ 1 error
注意- 由于 FileReader 类的方法read()和close()会抛出 IOException,因此您可以观察到编译器通知处理 IOException 以及 FileNotFoundException。
未经检查的异常- 未经检查的异常是在执行时发生的异常。这些也称为运行时异常。其中包括编程错误,例如逻辑错误或 API 使用不当。编译时忽略运行时异常。
例如,如果您在程序中声明了一个大小为 5 的数组,并尝试调用该数组的第 6个元素,则会发生ArrayIndexOutOfBoundsException异常。
例子
public class Unchecked_Demo { public static void main(String args[]) { int num[] = {1, 2, 3, 4}; System.out.println(num[5]); } }
如果编译并执行上述程序,您将得到以下异常。
输出
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
错误- 这些根本不是异常,而是超出用户或程序员控制范围的问题。代码中的错误通常会被忽略,因为您很少对错误采取任何措施。例如,如果发生堆栈溢出,就会出现错误。它们在编译时也会被忽略。
异常层次结构
所有异常类都是 java.lang.Exception 类的子类型。异常类是 Throwable 类的子类。除了异常类之外,还有另一个名为 Error 的子类,它派生自 Throwable 类。
错误是严重故障时发生的异常情况,Java 程序不处理这些情况。生成错误表示运行时环境产生的错误。示例:JVM 内存不足。通常,程序无法从错误中恢复。
Exception类有两个主要子类:IOException类和RuntimeException类。
异常方法
以下是 Throwable 类中可用的重要方法的列表。
先生。 | 方法及说明 |
---|---|
1 | 公共字符串 getMessage() 返回有关已发生的异常的详细消息。该消息在 Throwable 构造函数中初始化。 |
2 | 公共 Throwable getCause() 返回由 Throwable 对象表示的异常原因。 |
3 | 公共字符串 toString() 返回与 getMessage() 结果连接的类的名称。 |
4 | 公共无效 printStackTrace() 将 toString() 的结果与堆栈跟踪一起打印到 System.err(错误输出流)。 |
5 | 公共 StackTraceElement [] getStackTrace() 返回一个包含堆栈跟踪上每个元素的数组。索引 0 处的元素表示调用堆栈的顶部,数组中的最后一个元素表示调用堆栈底部的方法。 |
6 | 公共 Throwable fillInStackTrace() 使用当前堆栈跟踪填充此 Throwable 对象的堆栈跟踪,并添加到堆栈跟踪中的任何先前信息。 |
捕获异常
方法使用try和catch关键字的组合来捕获异常。try/catch 块放置在可能生成异常的代码周围。try/catch 块中的代码称为受保护代码,使用 try/catch 的语法如下所示 -
句法
try { // Protected code } catch (ExceptionName e1) { // Catch block }
容易出现异常的代码放在try块中。当异常发生时,发生的异常由与其关联的 catch 块处理。每个 try 块后面都应该紧跟着一个 catch 块或finally 块。
catch 语句涉及声明您尝试捕获的异常类型。如果受保护的代码中发生异常,则检查 try 后面的 catch 块(或多个块)。如果发生的异常类型在 catch 块中列出,则异常将传递到 catch 块,就像将参数传递到方法参数一样。
例子
在以下示例中,声明了一个包含 2 个元素的数组。然后代码尝试访问抛出异常的数组的第三个元素。
// File Name : ExcepTest.java import java.io.*; public class ExcepTest { public static void main(String args[]) { try { int a[] = new int[2]; System.out.println("Access element three :" + a[3]); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Exception thrown :" + e); } System.out.println("Out of the block"); } }
输出
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 Out of the block
多个 Catch 块
一个 try 块后面可以跟多个 catch 块。多个 catch 块的语法如下所示 -
句法
try { // Protected code } catch (ExceptionType1 e1) { // Catch block } catch (ExceptionType2 e2) { // Catch block } catch (ExceptionType3 e3) { // Catch block }
前面的语句演示了三个 catch 块,但在一次尝试后您可以拥有任意数量的 catch 块。如果受保护的代码中发生异常,则该异常将被抛出到列表中的第一个 catch 块。如果抛出的异常的数据类型与 ExceptionType1 匹配,则会在那里捕获该异常。如果不是,则异常将传递到第二个 catch 语句。这种情况会持续下去,直到异常被捕获或通过所有捕获,在这种情况下,当前方法停止执行,并将异常抛出到调用堆栈上的前一个方法。
例子
这是显示如何使用多个 try/catch 语句的代码段。
try { file = new FileInputStream(fileName); x = (byte) file.read(); } catch (IOException i) { i.printStackTrace(); return -1; } catch (FileNotFoundException f) // Not valid! { f.printStackTrace(); return -1; }
捕获多种类型的异常
从 Java 7 开始,您可以使用单个 catch 块处理多个异常,这一功能简化了代码。以下是你将如何做到的 -
catch (IOException|FileNotFoundException ex) { logger.log(ex); throw ex;
抛出/抛出关键字
如果方法不处理检查异常,则该方法必须使用throws关键字声明它。throws 关键字出现在方法签名的末尾。
您可以使用throw关键字抛出异常,可以是新实例化的异常,也可以是刚刚捕获的异常。
尝试理解 throws 和 throw 关键字之间的区别,throws用于推迟检查异常的处理,而throw用于显式调用异常。
以下方法声明它抛出 RemoteException -
例子
import java.io.*; public class className { public void deposit(double amount) throws RemoteException { // Method implementation throw new RemoteException(); } // Remainder of class definition }
一种方法可以声明它抛出多个异常,在这种情况下,异常在以逗号分隔的列表中声明。例如,以下方法声明它抛出 RemoteException 和 InsufficientFundsException -
例子
import java.io.*; public class className { public void withdraw(double amount) throws RemoteException, InsufficientFundsException { // Method implementation } // Remainder of class definition }
最后一块
finally 块位于 try 块或 catch 块之后。无论是否发生异常,finally 代码块始终都会执行。
使用finally 块允许您运行任何您想要执行的清理类型语句,无论受保护的代码中发生什么情况。
finally 块出现在 catch 块的末尾,并具有以下语法 -
句法
try { // Protected code } catch (ExceptionType1 e1) { // Catch block } catch (ExceptionType2 e2) { // Catch block } catch (ExceptionType3 e3) { // Catch block }finally { // The finally block always executes. }
例子
public class ExcepTest { public static void main(String args[]) { int a[] = new int[2]; try { System.out.println("Access element three :" + a[3]); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Exception thrown :" + e); }finally { a[0] = 6; System.out.println("First element value: " + a[0]); System.out.println("The finally statement is executed"); } } }
输出
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 First element value: 6 The finally statement is executed
请注意以下事项 -
如果没有 try 语句,catch 子句就不能存在。
只要存在 try/catch 块,就不必有finally 子句。
如果没有 catch 子句或finally 子句,则不能出现 try 块。
try、catch、finally 块之间不能出现任何代码。
尝试资源
一般来说,当我们使用流、连接等任何资源时,我们必须使用finally块显式关闭它们。在下面的程序中,我们使用FileReader从文件中读取数据,并使用 finally 块关闭它。
例子
import java.io.File; import java.io.FileReader; import java.io.IOException; public class ReadData_Demo { public static void main(String args[]) { FileReader fr = null; try { File file = new File("file.txt"); fr = new FileReader(file); char [] a = new char[50]; fr.read(a); // reads the content to the array for(char c : a) System.out.print(c); // prints the characters one by one } catch (IOException e) { e.printStackTrace(); }finally { try { fr.close(); } catch (IOException ex) { ex.printStackTrace(); } } } }
try-with-resources也称为自动资源管理,是 Java 7 中引入的一种新的异常处理机制,它会自动关闭 try catch 块内使用的资源。
要使用此语句,您只需在括号内声明所需的资源,创建的资源将在块末尾自动关闭。以下是 try-with-resources 语句的语法。
句法
try(FileReader fr = new FileReader("file path")) { // use the resource } catch () { // body of catch } }
以下是使用 try-with-resources 语句读取文件中的数据的程序。
例子
import java.io.FileReader; import java.io.IOException; public class Try_withDemo { public static void main(String args[]) { try(FileReader fr = new FileReader("E://file.txt")) { char [] a = new char[50]; fr.read(a); // reads the contentto the array for(char c : a) System.out.print(c); // prints the characters one by one } catch (IOException e) { e.printStackTrace(); } } }
使用 try-with-resources 语句时应牢记以下几点。
要使用带有 try-with-resources 语句的类,它应该实现AutoCloseable接口,并且它的close()方法在运行时自动调用。
您可以在 try-with-resources 语句中声明多个类。
当您在 try-with-resources 语句的 try 块中声明多个类时,这些类将以相反的顺序关闭。
除了括号内的资源声明之外,所有内容都与 try 块的正常 try/catch 块相同。
try 中声明的资源在 try 块开始之前被实例化。
在 try 块中声明的资源被隐式声明为 Final。
用户定义的异常
您可以在 Java 中创建自己的异常。编写自己的异常类时请记住以下几点 -
所有异常都必须是 Throwable 的子级。
如果要编写由 Handle 或 Declare Rule 自动强制执行的已检查异常,则需要扩展 Exception 类。
如果要编写运行时异常,则需要扩展 RuntimeException 类。
我们可以定义自己的异常类,如下所示 -
class MyException extends Exception { }
您只需要扩展预定义的异常类即可创建您自己的异常。这些被认为是检查异常。以下InsufficientFundsException类是一个用户定义的异常,它扩展了 Exception 类,使其成为受检查的异常。异常类与任何其他类一样,包含有用的字段和方法。
例子
// File Name InsufficientFundsException.java import java.io.*; public class InsufficientFundsException extends Exception { private double amount; public InsufficientFundsException(double amount) { this.amount = amount; } public double getAmount() { return amount; } }
为了演示如何使用用户定义的异常,以下 CheckingAccount 类包含一个会抛出 InsufficientFundsException 的withdraw() 方法。
// File Name CheckingAccount.java import java.io.*; public class CheckingAccount { private double balance; private int number; public CheckingAccount(int number) { this.number = number; } public void deposit(double amount) { balance += amount; } public void withdraw(double amount) throws InsufficientFundsException { if(amount <= balance) { balance -= amount; }else { double needs = amount - balance; throw new InsufficientFundsException(needs); } } public double getBalance() { return balance; } public int getNumber() { return number; } }
以下BankDemo程序演示了调用CheckingAccount的deposit()和withdraw()方法。
// File Name BankDemo.java public class BankDemo { public static void main(String [] args) { CheckingAccount c = new CheckingAccount(101); System.out.println("Depositing $500..."); c.deposit(500.00); try { System.out.println("\nWithdrawing $100..."); c.withdraw(100.00); System.out.println("\nWithdrawing $600..."); c.withdraw(600.00); } catch (InsufficientFundsException e) { System.out.println("Sorry, but you are short $" + e.getAmount()); e.printStackTrace(); } } }
编译以上三个文件并运行BankDemo。这将产生以下结果 -
输出
Depositing $500... Withdrawing $100... Withdrawing $600... Sorry, but you are short $200.0 InsufficientFundsException at CheckingAccount.withdraw(CheckingAccount.java:25) at BankDemo.main(BankDemo.java:13)
常见异常
在 Java 中,可以定义异常和错误两类。
JVM 异常- 这些是 JVM 专门或逻辑抛出的异常/错误。示例:NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException。
编程异常- 这些异常由应用程序或 API 程序员显式抛出。示例:IllegalArgumentException、IllegalStateException。