异常(或异常事件)是在执行程序期间出现的问题。 当发生异常时,程序的正常流程被中断并且程序/应用程序异常终止,这是对于用户来说是非常不友好的。因此,要合理地处理这些异常。
发生异常有许多不同的原因,以下是发生异常的一些情况。
有一些异常是由用户错误引起的,也有一些异常是由程序员错误引起的,或者是由以某种物理资源引起的。
基于这三类异常,您需要了解它们以了解在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个元素,则会发生arrayindexoutofboundsexceptionexception异常。
public class unchecked_demo {
public static void main(string args[]) {
int num[] = {1, 2, 3, 4};
system.out.println(num[5]);// 访问第6个元素
}
}
如果编译并执行上述程序,则会出现以下异常。
exception in thread "main" java.lang.arrayindexoutofboundsexception: 5
at exceptions.unchecked_demo.main(unchecked_demo.java:8)
错误 - 这个严格来说不是异常,它是超出用户或程序员控制的问题。 代码中通常会忽略错误,因为很少对错误做任何事情。 例如,如果发生堆栈溢出,则会出现错误。 它们在编译时也被忽略。
所有异常类都是java.lang.exception类的子类型。 exception类是throwable类的子类。 除了exception类之外,还有另一个名称为error的子类,它派生自throwable类。
错误是在严重故障的情况下发生的异常情况,java程序不处理这些情况。 生成错误以指示运行时环境生成的错误。例如:jvm内存不足。 通常,程序无法从错误中恢复。
exception类有两个主要的子类:ioexception类和runtimeexception类。
以下是最常见的已检查和未检查的java内置异常类列表。
以下是throwable类中可用的方法列表。
| 编号 | 方法 | 异常 |
|---|---|---|
| 1 | public string getmessage() |
返回有关已发生的异常的详细消息,此消息在throwable构造函数中初始化。 |
| 2 | public throwable getcause() |
返回由throwable对象表示的异常的原因。 |
| 3 | public string tostring() |
返回与getmessage()结果连接的类名称。 |
| 4 | public void printstacktrace() |
将tostring()的结果与堆栈跟踪一起打印到system.err(错误输出流)。 |
| 5 | public stacktraceelement [] getstacktrace() |
返回包含堆栈跟踪上每个元素的数组。 索引0处的元素表示调用堆栈的顶部,而数组中的最后一个元素表示调用堆栈底部的方法。 |
| 6 | public 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个元素声明的数组,然后尝试访问引发异常的数组的第3个元素。
// 文件 : 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
try块后面可以跟多个catch块,多个catch块的语法如下所示 -
语法
try {
// protected code
} catch (exceptiontype1 e1) {
// catch block
} catch (exceptiontype2 e2) {
// catch block
} catch (exceptiontype3 e3) {
// catch block
}
上面的语句中放置了三个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
使用finally时,需要注意以下规则 -
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-block开始之前实例化。try块声明的资源被隐式声明为final。可以在java中创建自己的异常。 在编写自己的异常类时,请注意以下几点 -
throwable的子类。exception类。runtimeexception类。可以定义自己的exception类,如下所示 -
class myexception extends exception {
}
只需要扩展预定义的exception类来创建自己的exception类。 这些都是经过检查的异常。 以下insufficientfundsexception类是一个用户定义的异常,它扩展了exception类,使其成为一个已检查的异常。异常类与任何其他类一样,包含有用的字段和方法。
示例
// 文件: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类的withdraw()方法中包含抛出insufficientfundsexception。
// 文件名称: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()方法。
// 文件: 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();
}
}
}
执行上面示例代码,得到以下结果 -
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中,可以定义两个分类:异常和错误。
nullpointerexception,arrayindexoutofboundsexception,classcastexception。illegalargumentexception,illegalstateexception。