JAVA中的异常类都继承自Throwable类,也就是说,这是异常类的根。Throwable类扩展了两个类Error类和Exception类,Exception类又扩展了一个RuntimeException类。以下图:javascript
通常来讲,出现RuntimeException异常表示的是代码不合理而出现的问题。php
所以,在自定义异常类型时,大多数都直接继承Exception类,偶尔可能继承RuntimeException类,更偶尔的可能会继承这些类的某些子类。css
使用try-catch结构捕捉异常,并设置捕捉到后的处理方式。还能够加上finally结构,这是可选结构,但却表示try结构中必须会被执行的部分。html
如下是try-catch-finally结构和处理过程的分析。java
try {
// 待捕捉测试的代码1
// 待捕捉测试的代码2 (假设此为异常代码,将抛出名为异常名2的异常)
// 待捕捉测试的代码3
} catch (异常名1 对象名e) {
// 捕捉到异常名1的异常后,该作的处理代码4
} catch (异常名2 对象名e) {
// 捕捉到异常名2的异常后,该作的处理代码5
} ... {
//...
} finally {
//必定会执行的代码6
}
//try结构外的代码7
前提假设,在各代码中没有return子句。执行过程为:首先代码1正常执行,到代码2处抛出异常名2的异常,经过异常名匹配,将选择第二个catch结构,因而将异常2封装到对象名e中,并执行代码5处理异常。catch部分处理完后,还有最后处理段finally,因而执行代码6。出了finally后,还将执行代码7。nginx
注意,当代码2出现异常后,代码3不会执行。而finally则是不管是否真的捕捉到了异常、是否在catch段有return都会执行的代码段。换句话说,finally段的代码除了内部错误或外界影响都必定会执行。就像下面的例子中,即便catch使用了return,但finally仍是会执行,只不过这个catch终止了try结构外的代码。git
例如,除数为0时会抛出ArithmeticException异常。try-catch捕捉它:github
public class TEx {
public static void main(String[] args) {
try {
System.out.println("[start]");
System.out.println(2/0);
System.out.println("[end]");
} catch (ArithmeticException e) {
System.out.println("[Catching]: " + e);
return;
} finally {
System.out.println("[Finally]");
}
System.out.println("[out of try-catch]");
}
}
在finally段中还能够继续try-catch-finally,防止该段落的代码再次抛出异常。web
public class TEx {
public static void main(String[] args) {
try {
System.out.println("[start]");
System.out.println(2/0);
System.out.println("[end]");
} catch (ArithmeticException e) {
System.out.println("[Catching]: " + e);
return;
} finally {
try {
System.out.println("[Finally-try-start]");
System.out.println(3/0);
} catch (ArithmeticException e) {
System.out.println("[Finally-Catching]: " + e);
}
}
System.out.println("[out of try-catch]");
}
}
java中的异常都会封装到对象中。异常对象中有几个方法:django
throw关键字用于在某个语句处抛出一个异常,只要执行到这个语句就表示一定抛出异常。
throws关键字用于在方法处抛出一个或多个异常,这表示执行这个方法可能会抛出异常。
throw OBJECT;
throw new EXCEPTION("Message");
method() throws EXCEPTION1[,EXCEPTION2...] {}
对于Exception类(非RuntimeException)的异常即已检查异常类,在调用时要么进行捕捉,要么继续向上级抛出。这类错误产生和处理的过程为:
如下是抛出异常的一个简单示例,抛出的是ArithmeticException异常,由于是RuntimeException类异常,所以从方法体内部throw抛出后,无需在方法定义处使用throws继续抛出。
public class EX {
void f(int n) { // 或void f(int n) throws ArithmeticException {}
if (n == 0) {
throw new ArithmeticException("hello Exception!");
} else {
System.out.println("right!");
}
}
public static void main(String[] args) {
EX m = new EX();
m.f(1);
m.f(0); // throw Exception
}
}
执行结果:
right!
Exception in thread "main" java.lang.ArithmeticException: hello Exception! //异常的信息
at EX.f(EX.java:4) //真实产生异常的地方
at EX.main(EX.java:13) //调用产生异常的地方
因此,对于RuntimeException类异常来讲,是否使用throws关键字并没有影响。通常来讲,Exception类异常但非RuntimeException才须要使用throws关键字,由于Exception类异常必需要被捕获并处理,而RuntimeException异常则无所谓。
例如将上面的ArimeticException改成FileNotFoundException,前者为Runtime类异常,然后者为Exception但非Runtime类异常,所以使用throw抛出后,必须在定义方法处也使用throws抛出错误。这一过程是"向上级抛出"的过程:"方法体内部抛出异常-->抛给方法自己"。
void f(int n) throws FileNotFoundException {
if (n == 0) {
throw new FileNotFoundException("hello Exception!"); //throw a new yichang duixiang
} else {
System.out.println("right!");
}
}
若是不使用throws关键字抛出错误,则将报错:
EX.java:6: 错误: 未报告的异常错误FileNotFoundException; 必须对其进行捕获或声明以便抛出
throw new FileNotFoundException("hello Exception!"); //throw a new yichang duixiang
从方法f()抛出向上抛出给调用者后,调用者要么使用try-catch捕捉,要么继续向上抛出,不然报错。例如捕捉
import java.io.*;
public class EX {
void f(int n) throws FileNotFoundException {
if (n == 0) {
throw new FileNotFoundException("hello Exception!");
} else {
System.out.println("right!");
}
}
public static void main(String[] args) {
try {
EX m = new EX();
m.f(0);
} catch (FileNotFoundException e) {
System.out.println(e);
}
System.out.println("out of try-catch");
}
}
若是不捕捉,则能够继续在方法处向上抛出:
public static void main(String[] args) throws FileNotFoundException {
EX m = new EX();
m.f(0);
}
throw能够同时定义可能抛出的多种异常,尽管这些异常存在继承关系。这时在捕捉异常时,应该先捕捉子类,再捕捉父类。
例如FileNotFoundException是IOException的子类,能够同时:
throws FileNotFoundException,IOException
捕捉时应先捕捉FileNotFoundException,再IOException。
try {
...
} catch (FileNotFoundException e) {
...
} catch (IOException e) {
...
}
在重写有throws子句的方法时,须要注意:
因此下面的定义中,前子类1-3重写和子类5-7都是有效的,但子类4重写是错误的。
父类:method() throws IOException {} 子类1:method() throws {} 子类2:method() throws IOException {} 子类3:method() throws FileNotFoundException {} 子类4:method() throws Exception {} 子类5:method() throws RuntimeException {} 子类6:method() throws IOException,RuntimeException {} 子类7:method() throws IOException,ArithmeticException {}
异常是类,当产生异常时会构建此类的异常对象。
自定义异常时须要考虑异常类的构造方法是否接参数,参数须要如何处理实现怎样的逻辑。
自定义的异常通常都从Exception继承。
例以下面定义了一个银行卡存、取钱时的程序,其中自定义了一个Exception类错误。
// User Define Exception
class OverDrawException extends Exception {
private double amount;
public OverDrawException(double amount) {
this.amount = amount;
}
public OverDrawException(String message) {
super(message);
}
public double getAmount() {
return amount;
}
}
// Card class
class Card {
//cardNum:卡号,balance:余额
private String cardNum;
private double balance;
Card(String n,double b) {
this.cardNum = n;
this.balance = b;
}
//方法:存钱
public void cunQian(double n) {
balance += n;
}
//方法:取钱
public void quQian(double n) throws OverDrawException {
if (n <= this.balance) {
balance -= n;
} else {
double need = n - balance;
throw new OverDrawException(need);
}
}
//方法:返回余额
public double getBalance() {
return this.balance;
}
}
public class SuanZhang {
public static void main(String [] args) {
try {
Card card = new Card("62202",300);
System.out.println("卡里余额:" + card.getBalance());
//存钱
card.cunQian(200);
System.out.println("余额:" + card.getBalance());
//取钱
card.quQian(600);
System.out.println("余额:" + card.getBalance());
} catch (OverDrawException e) {
System.out.println(e);
System.out.println("抱歉!您的余额不足,缺乏:" + e.getAmount());
}
}
}
注:若您以为这篇文章还不错请点击右下角推荐,您的支持能激发做者更大的写做热情,很是感谢!