电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

异常处理机制-Exception


发布日期:2023/9/22
 

简介

Java为我们提供了非常完美的异常处理机制使得我们可以更加专心的去写程序有的时候遇到需要添加异常处理块的地方像eclipse会自动提示你感觉很幸福!我们看看异常处理的一些类的结构组成

从根部开始分为两大类Error和ExceptionError是程序无法处理的错误比如OutOfMemoryErrorThreadDeath等这些异常发生时Java虚拟机(JVM)一般会选择线程终止Exception是程序本身可以处理的异常这种异常分两大类非运行时异常(发生在编译阶段又称checkException)和运行时异常(发生在程序运行过程中又叫uncheckException)非运行时异常一般就是指一些没有遵守Java语言规范的代码容易看的出来并且容易解决的异常运行时异常是那些在程序运行过程中产生的异常具有不确定性如空指针异常等造成空指针的原因很多所以运行时异常具有不确定性往往难以排查还有就是程序中存在的逻辑错误光从一段代码中看不出问题需要纵观全局才能发现的错误也会造成运行时异常这就要求我们在写程序时多多注意尽量处理去处理异常当异常发生时希望程序能朝理想的方面运行!

异常的类型

一方面我们可以将异常分为受控异常和不受控异常其实一般来讲受控异常就是非运行时异常不受控异常就是运行时异常和Error另一方面我们直接将异常分为非运行时异常和运行时异常

异常处理的过程

使用try/catch/finally语句块安装异常处理程序每个try块中包含可能出现异常的语句每个catch块中包含处理异常的程序

public class Test {

public static void main(String[] args) {

String filename = d:\\testtxt;

try {

FileReader reader = new FileReader(filename)

Scanner in = new Scanner(reader)

String input = innext()

int value = IntegerparseInt(input)

Systemoutprintln(value)

} catch (FileNotFoundException e) {

eprintStackTrace()

} finally {

Systemoutprintln(this is finally block!

}

}

}

如果d盘根目录下没有testtxt的话该程序抛出异常

this is finally block!

javaioFileNotFoundException: d:\testtxt (系统找不到指定的文件

at javaioFileInputStreamopen(Native Method)

at javaioFileInputStream<init>(FileInputStreamjava:

at javaioFileInputStream<init>(FileInputStreamjava:

at javaioFileReader<init>(FileReaderjava:

at Testmain(Testjava:

但是finally块中的语句却输出了这个暂且不谈先记着在d盘下新建文件testtxt并输入内容再来观察下

输出

this is finally block!

finally块中的语句依然输出说明不论程序有无异常finally块中的语句都会执行因此finally块中一般放一些关闭资源的语句接下来我们继续做实验我们将testtxt中的改成abc看看结果

this is finally block!

Exception in thread main javalangNumberFormatException: For input string: abc

at javalangNumberFormatExceptionforInputString(NumberFormatExceptionjava:

at javalangIntegerparseInt(Integerjava:

at javalangIntegerparseInt(Integerjava:

at Testmain(Testjava:

该异常中的两处重点我已经标出来了一处是红色的Exception in thread main表明异常抛出的地方另一处是javalangNumberFormatException: For input string: abc表明异常的类型此处我们看看上面之前的那个结果为什么没有抛出异常出现的地方仔细观察源程序我们发现程序中我们并没有显式声明NumberFormatException而FileNotFoundException是我们声明过的此处我总结一下就是说如果我在程序中声明了某个异常则抛出异常的时候不会显式出处直接抛出如果我没有在程序中声明那么程序会同时抛出异常的出处这是为什么?还有当我没有显式声明的时候系统会怎么办?这肯定是有一定的规律的下面我们继续做实验

[java]

public class Test {

public static void main(String[] args) {

String filename = d:\\testtxt;

// 进行捕捉异常

try {

FileReader reader = new FileReader(filename)

Scanner in = new Scanner(reader)

String input = innext()

int value = IntegerparseInt(input)

Systemoutprintln(value)

} catch (FileNotFoundException e) { // 捕捉FileNotFoundException

eprintStackTrace()

} catch (NumberFormatException e) { // NumberFormatException

eprintStackTrace() // 打印异常信息 就是形如at javalangNumberFor…的信息

Systemoutprintln(Im here!

} finally {

Systemoutprintln(this is finally block!

}

}

}

我加了一个catch块转么捕获NumberFormatException则程序输出

javalangNumberFormatException: For input string: abc

at javalangNumberFormatExceptionforInputString(NumberFormatExceptionjava:

at javalangIntegerparseInt(Integerjava:

at javalangIntegerparseInt(Integerjava:

at Testmain(Testjava:

Im here!

this is finally block!

没有输出异常抛出的地方继续改代码

[java]

public class Test {

public void open(){

String filename = d:\\testtxt;

try {

FileReader reader = new FileReader(filename)

Scanner in = new Scanner(reader)

String input = innext()

int value = IntegerparseInt(input)

Systemoutprintln(value)

} catch (FileNotFoundException e) {

eprintStackTrace()

Systemoutprintln(this is test block!

}

}

}

[java]

public class Test {

public void carry() {

Test t = new Test()

try {

topen()

} catch (Exception e) {

eprintStackTrace()

Systemoutprintln(this is test block!

}

}

}

[java]

public class Test {

public static void main(String[] args) {

Test t = new Test()

tcarry()

}

}

思路是Test类中处理业务Test类调用Test类的open方法最后在Test类中调用Test类的carry方法但是我将异常抛在Test看看异常输出的结果

javalangNumberFormatException: For input string: abc

at javalangNumberFormatExceptionforInputString(NumberFormatExceptionjava:

at javalangIntegerparseInt(Integerjava:

at javalangIntegerparseInt(Integerjava:

at Testopen(Testjava:

at Testcarry(Testjava:

at Testmain(Testjava:

this is test block!

首先抛出的异常没有地方信息了其次输出了this is test block!说明该异常是从Test类中的carry方法抛出的当我们把Test类中的异常捕获语句注释掉的时候异常如下

Exception in thread main javalangNumberFormatException: For input string: abc

at javalangNumberFormatExceptionforInputString(NumberFormatExceptionjava:

at javalangIntegerparseInt(Integerjava:

at javalangIntegerparseInt(Integerjava:

at Testopen(Testjava:

at Testcarry(Testjava:

at Testmain(Testjava:

看到此处我想读者朋友们应该有一定的感觉了说了这么多就是想说明一点当程序处理不了异常的时候会怎么办?是这样的当前方法如果声明了相应的异常处理器如上面的程序如果加了catch(NumberFormatException e)则直接抛出但是如果没有声明则会找到它的调用者如果调用者也没有做相应的处理则会一直往前找直到找到main方法最后抛出异常所以上面的现象不难解释!此处我们简单总结下异常处理的过程在可能出错的方法加上try/catch块语句来调用异常处理器当异常发生时直接跳到相应的异常处理器catch中如果有则抛出异常执行该catch块中的语句如果没哟则找到它的调用者直到main方法如果有finally块则执行finally块中的语句

注意

一个try可对应多个catch有try必须至少有一个catchfinally块不是必须的可有可无一般情况下当异常发生时会执行catch块中的语句特殊情况当main方法中抛出异常时如果程序声明了该异常处理器则执行相应的catch块中的语句如果程序没有声明相应的异常处理器则不执行catch块中的语句直接抛出异常!那么这个异常来源于哪儿?既然main中有try/catch语句(虽然不是对应的异常处理器)为什么没有抛出说明main方法中的try/catch块根本就没有捕捉到异常那么系统怎么处理?其实是这样的这种情况下异常被直接丢给JVM而JVM的处理方式就是直接中断你的程序!就是这么简单

常见异常

NullPointerException 空指针

空指针异常当应用试图在要求使用对象的地方使用了null时抛出该异常譬如调用null对象的实例方法访问null对象的属性计算null对象的长度使用throw语句抛出null等等

ClassNotFoundException 找不到类

找不到类异常当应用试图根据字符串形式的类名构造类而在遍历CLASSPAH之后找不到对应名称的class文件时抛出该异常

ClassCastException 类型转换

ArithmeticException 算数条件

算术条件异常譬如整数除零等

ArrayIndexOutOfBoundsException 数组越界

数组索引越界异常当对数组的索引值为负数或大于等于数组大小时抛出

这块内容我们会不断更新请读者朋友们在阅读的同时不断提出自己遇到的有意义的异常不断充实博文欢迎读者积极补充!

有任何问题请联系egg

异常和错误

异常 在Java中程序的错误主要是语法错误和语义错误一个程序在编译和运行时出现的错误我们统一称之为异常它是JVM(Java虚拟机)通知你的一种方式通过这种方式JVM让你知道你已经犯了个错误现在有一个机会来修改它Java中使用异常类来表示异常不同的异常类代表了不同的异常但是在Java中所有的异常都有一个基类叫做Exception

错误它指的是一个合理的应用程序不能截获的严重的问题大多数都是反常的情况错误是JVM的一个故障(虽然它可以是任何系统级的服务)所以错误是很难处理的一般的开发人员是无法处理这些错误的比如内存溢出

Assert(断言)

assert是jdk才开始支持的新功能主要在开发和测试时开启为保证性能在程序正式发布后通常是关闭的启用断言比较简单在启动参数里设置ea或者enableassertions就可以了

assert表达式有两种情况

)assert exp 此时的exp为一个boolean类型的表达式

当其值为true时运行通过如果为false则会抛出一个相应的AssertionError注意它可以被catch到

)assert exp : exp 此时的exp同上而exp可以为基本类型或一个Object对象当exp的值为true时同上且exp不会被运算而当exp的值为false时将会抛出AssertionError同时将exp的结果作为AssertionError构造器中的参数当使用catch该错误时可利用getMessage()方法打印出exp的结果

使用断言应该注意断言只是用来调试程序的工具不要作为程序的一部分或者有人用断言来代替try/catch这些都是不对的这和断言的作用相违背断言在程序发布后是会被关闭的如果将它作为程序的一部分那么当断言被关闭后程序必然会出问题有更好的方法如try/catch为什么还用断言所以最好不要讲断言作为程序的一部分从心里上你可以把它当做可有可无就行了

常见问题

finally和return问题

我们平时说finally中的内容不论程序有无异常都会被执行那么如果我们的程序在try和catch块中return了finally中的还会执行吗?读者可以先猜猜看分析一下接下来我们做实验

[java]

public class FinallyTest {

public static void main(String[] args) {

boolean file = open()

Systemoutprintln(this is main return value: + file)

}

public static boolean open() {

String filename = d:\\testtxtp;

try {

FileReader reader = new FileReader(filename)

Scanner in = new Scanner(reader)

String input = innext()

int value = IntegerparseInt(input)

Systemoutprintln(value)

return true;

} catch (FileNotFoundException e) {

Systemoutprintln(this is catch_for_filenot… block!

return false;

} finally {

Systemoutprintln(this is finally block!

}

}

}

故意把filename写错造出异常输出为下

this is catch_for_filenot… block!

this is finally block!

this is main return value:false

从这儿看出来程序先输出catch块中的后又去执行finally块中的虽然在catch中已经返回了最后执行mian方法中的而且输出false说明catch块中的也成功返回了所以面对疑问我们可以很肯定的回答即使有return语句finally块也一定会被执行!

尽量不要将catch和finally一起使用

像我上面演示程序那样try/catch/finally一起使用在《Big Java》一书中提到不建议这样做因为会影响程序的可读性最好的做法是用try/catch嵌套catch用来捕获异常finally用来关闭资源修改如下

[java]

public class FinallyTest {

public static void main(String[] args) {

boolean file = open()

Systemoutprintln(this is main return value: + file)

}

public static boolean open() {

String filename = d:\\testtxtp;

try {

try {

FileReader reader = new FileReader(filename)

Scanner in = new Scanner(reader)

String input = innext()

int value = IntegerparseInt(input)

Systemoutprintln(value)

return true;

} finally {

// 一些关闭资源的操作

Systemoutprintln(this is finally block!

}

} catch (FileNotFoundException e) {

Systemoutprintln(this is catch_for_filenot… block!

return false;

}

}

}

自定义异常

毕竟系统自带的异常处理器并不能满足所有需求因为对于我们开发人员来说抛出的异常越细致我们越容易找到问题总不能所有的问题都抛出Exception吧?太笼统了在实际的开发中我们可以根据自己的需要进行自定义异常处理器

[java]

/**

* 自定义异常处理器继承Exception或者RuntimeException依情况而定

* @author erqing

*

*/

public class NameNotSupportException extends RuntimeException {

private static final long serialVersionUID = L;

public NameNotSupportException() {

}

public NameNotSupportException(String message) {

super(message)

}

}

[java]

public class DefineTest {

public static void main(String[] args) {

String name = egg;

if(!erqingequals(name)){

throw new NameNotSupportException(erqing

}else{

Systemoutprintln(name is OK!

}

}

}

[java]

Exception in thread main NameNotSupportException: erqing

at DefineTestmain(DefineTestjava:

上一篇:继承protected

下一篇:用Scala实现Qt QWidget对象的Eventable接口