Java之Exception
Exception这个东西,程序中必须会有的,尽管我们很不乐意看到它,可是从另一个角度考虑,有异常则说明程序有问题,有助于我们及时改正。有的时候程序出错的原因有很多,比如不合法的输入、类型、空指针甚至内存不足,如果光从软件来看,我们只知道它出问题了,并不清楚问题出在哪儿,给软件排错是个很头疼的事情,因为可能出问题的地方太多了,语法上的问题还好点儿,毕竟能从视觉上看出来,有些逻辑上的问题才是致命的,我们必须从全局出发也许才能找到问题的根源!
转自:http://blog.csdn.net/zhangerqing
一、简介
Java为我们提供了非常完美的异常处理机制,使得我们可以更加专心的去写程序,有的时候遇到需要添加异常处理块的地方,像eclipse会自动提示你,感觉很幸福!我们看看异常处理的一些类的结构组成:
从根部开始分为两大类:Error和Exception。Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。Exception是程序本身可以处理的异常,这种异常分两大类:非运行时异常(发生在编译阶段,又称checkException)和运行时异常(发生在程序运行过程中,又叫uncheckException)。非运行时异常一般就是指一些没有遵守Java语言规范的代码,容易看的出来,并且容易解决的异常,运行时异常是那些在程序运行过程中产生的异常,具有不确定性,如空指针异常等,造成空指针的原因很多,所以运行时异常具有不确定性,往往难以排查,还有就是程序中存在的逻辑错误,光从一段代码中看不出问题,需要纵观全局才能发现的错误,也会造成运行时异常,这就要求我们在写程序时多多注意,尽量处理去处理异常,当异常发生时,希望程序能朝理想的方面运行!
二、异常的类型
一方面我们可以将异常分为受控异常和不受控异常,其实一般来讲,受控异常就是非运行时异常,不受控异常就是运行时异常和Error。另一方面,我们直接将异常分为非运行时异常和运行时异常。
三、异常处理的过程
使用try/catch/finally语句块安装异常处理程序,每个try块中包含可能出现异常的语句,每个catch块中包含处理异常的程序,
public class Test { public static void main(String[] args) {
String filename = "d:\\test.txt";
try {
FileReader reader = new FileReader(filename);
Scanner in = new Scanner(reader);
String input = in.next();
int value = Integer.parseInt(input);
System.out.println(value);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
System.out.println("this is finally block!");
}
}
}
如果d盘根目录下没有test.txt的话,该程序抛出异常:
this is finally block!
java.io.FileNotFoundException: d:\test.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:106)
at java.io.FileInputStream.<init>(FileInputStream.java:66)
at java.io.FileReader.<init>(FileReader.java:41)
at Test.main(Test.java:10)
但是finally块中的语句却输出了,这个暂且不谈,先记着,在d盘下新建文件test.txt,并输入内容2232,再来观察下:
输出:
2322
this is finally block!
finally块中的语句依然输出,说明:不论程序有无异常,finally块中的语句都会执行。因此finally块中一般放一些关闭资源的语句。接下来我们继续做实验,我们将test.txt中的2322改成abc,看看结果:
this is finally block!
Exception in thread "main" java.lang.NumberFormatException: For input string: "abc"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:447)
at java.lang.Integer.parseInt(Integer.java:497)
at Test.main(Test.java:13)
该异常中的两处重点我已经标出来了,一处是红色的Exception in thread “main”,表明异常抛出的地方,另一处是java.lang.NumberFormatException: For input string: "abc",表明异常的类型,此处我们看看上面之前的那个结果,为什么没有抛出异常出现的地方,仔细观察源程序,我们发现,程序中我们并没有显式声明NumberFormatException,而FileNotFoundException是我们声明过的,此处我总结一下就是说:1、如果我在程序中声明了某个异常,则抛出异常的时候,不会显示出处,直接抛出。2、如果我没有在程序中声明,那么程序会同时抛出异常的出处。这是为什么?还有,当我没有显式声明的时候,系统会怎么办?这肯定是有一定的规律的,下面我们继续做实验:
public class Test { public static void main(String[] args) { String filename = "d:\\test.txt"; // 进行捕捉异常
try {
FileReader reader = new FileReader(filename);
Scanner in = new Scanner(reader);
String input = in.next();
int value = Integer.parseInt(input);
System.out.println(value);
} catch (FileNotFoundException e) { // 捕捉FileNotFoundException
e.printStackTrace();
} catch (NumberFormatException e) { // NumberFormatException
e.printStackTrace(); // 打印异常信息 就是形如:at java.lang.NumberFor...的信息
System.out.println("I'm here!");
} finally {
System.out.println("this is finally block!");
}
}
}
我加了一个catch块,转么捕获NumberFormatException,则程序输出:
java.lang.NumberFormatException: For input string: "abc"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:447)
at java.lang.Integer.parseInt(Integer.java:497)
at Test.main(Test.java:14)
I'm here!
this is finally block!
没有输出异常抛出的地方。继续改代码:
public class Test2 { public void open(){
String filename = "d:\\test.txt";
try {
FileReader reader = new FileReader(filename);
Scanner in = new Scanner(reader);
String input = in.next();
int value = Integer.parseInt(input);
System.out.println(value);
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("this is test2 block!");
}
}
}
public class Test3 { public void carry() {
Test2 t2 = new Test2();
try {
t2.open();
} catch (Exception e) {
e.printStackTrace();
System.out.println("this is test3 block!");
}
}
}
public class Test { public static void main(String[] args) { Test3 t3 = new Test3(); t3.carry();
} }
思路是:Test2类中处理业务,Test3类调用Test2类的open方法,最后在Test类中调用Test3类的carry方法,但是,我将异常抛在Test3中,看看异常输出的结果:
java.lang.NumberFormatException: For input string: "abc"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:447)
at java.lang.Integer.parseInt(Integer.java:497)
at Test2.open(Test2.java:13)
at Test3.carry(Test3.java:6)
at Test.main(Test.java:7)
this is test3 block!
首先,抛出的异常没有地方信息了,其次输出了:this is test3 block!,说明该异常是从Test3类中的carry方法抛出的,当我们把Test3类中的异常捕获语句注释掉的时候,异常如下:
Exception in thread "main" java.lang.NumberFormatException: For input string: "abc"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:447)
at java.lang.Integer.parseInt(Integer.java:497)
at Test2.open(Test2.java:13)
at Test3.carry(Test3.java:6)
at Test.main(Test.java:7)
看到此处,我想读者朋友们应该有一定的感觉了,说了这么多,就是想说明一点,当程序处理不了异常的时候会怎么办?是这样的:当前方法如果声明了相应的异常处理器,如上面的程序如果加了catch(NumberFormatException e),则直接抛出,但是如果没有声明,则会找到它的调用者,如果调用者也没有做相应的处理,则会一直往前找,直到找到main方法,最后抛出异常,所以上面的现象不难解释!此处我们简单总结下异常处理的过程:1、在可能出错的方法加上try/catch块语句,来调用异常处理器。2、当异常发生时,直接跳到相应的异常处理器catch中,如果有则抛出异常,执行该catch块中的语句,如果没有,则找到它的调用者,直到main方法。3、如果有finally块,则执行finally块中的语句。
注意:
1、一个try可对应多个catch。2、有try必须至少有一个catch或者finally(此处经网友actt001指正,多谢!)。3、finally块不是必须的,可有可无。4、一般情况下,当异常发生时,会执行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 数组越界
数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
五、异常和错误
异常: 在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是JVM(Java虚拟机)通知你的一种方式,通过这种方式,JVM让你知道,你已经犯了个错误,现在有一个机会来修改它。Java中使用异常类来表示异常,不同的异常类代表了不同的异常。但是在Java中所有的异常都有一个基类,叫做Exception。
错误:它指的是一个合理的应用程序不能截获的严重的问题,大多数都是反常的情况,错误是JVM的一个故障(虽然它可以是任何系统级的服务)。所以,错误是很难处理的,一般的开发人员是无法处理这些错误的,比如内存溢出。
六、Assert(断言)
assert是jdk1.4才开始支持的新功能,主要在开发和测试时开启,为保证性能,在程序正式发布后通常是关闭的。启用断言比较简单,在启动参数里设置-ea或者-enableassertions就可以了.
assert表达式有两种情况:
1)assert exp1 此时的exp1为一个boolean类型的表达式
当其值为true时,运行通过,如果为false,则会抛出一个相应的AssertionError,注意它可以被catch到。
2)assert exp1 : exp2 此时的exp1同上,而exp2可以为基本类型或一个Object对象,当exp1的值为true时,同上,且exp2不会被运算;而当exp1的值为false时,将会抛出AssertionError,同时将exp2的结果作为AssertionError构造器中的参数,当使用catch该错误时,可利用getMessage()方法打印出exp2的结果。
使用断言应该注意:断言只是用来调试程序的工具,不要作为程序的一部分,或者有人用断言来代替try/catch,这些都是不对的,1、这和断言的作用相违背,2、断言在程序发布后,是会被关闭的,如果将它作为程序的一部分,那么当断言被关闭后,程序必然会出问题。3、有更好的方法,如try/catch,为什么还用断言。所以,最好不要讲断言作为程序的一部分,从心里上你可以把它当做可有可无就行了。
七、常见问题
1、finally和return问题
我们平时说:finally中的内容不论程序有无异常,都会被执行,那么如果我们的程序在try和catch块中return了,finally中的还会执行吗?读者可以先猜猜看,分析一下,接下来我们做实验:
public class FinallyTest { public static void main(String[] args) {
boolean file = open();
System.out.println("this is main return value:" + file);
} public static boolean open() {
String filename = "d:\\test.txtp";
try {
FileReader reader = new FileReader(filename);
Scanner in = new Scanner(reader);
String input = in.next();
int value = Integer.parseInt(input);
System.out.println(value);
return true; } catch (FileNotFoundException e) {
System.out.println("this is catch_for_filenot... block!");
return false;
} finally {
System.out.println("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块也一定会被执行!
2、尽量不要将catch和finally一起使用
像我上面演示程序那样,try/catch/finally一起使用,在《Big Java》一书中提到,不建议这样做,因为会影响程序的可读性,最好的做法是:用try/catch嵌套,catch用来捕获异常,finally用来关闭资源,修改如下:
public class FinallyTest { public static void main(String[] args) { boolean file = open();
System.out.println("this is main return value:" + file);
} public static boolean open() { String filename = "d:\\test.txtp";
try {
try {
FileReader reader = new FileReader(filename);
Scanner in = new Scanner(reader);
String input = in.next();
int value = Integer.parseInt(input);
System.out.println(value);
return true; } finally {
// 一些关闭资源的操作
System.out.println("this is finally block!");
} } catch (FileNotFoundException e) {
System.out.println("this is catch_for_filenot... block!");
return false;
}
}
}
3、自定义异常
毕竟系统自带的异常处理器并不能满足所有需求,因为对于我们开发人员来说,抛出的异常越细致,我们越容易找到问题,总不能所有的问题都抛出Exception吧?太笼统了。在实际的开发中,我们可以根据自己的需要,进行自定义异常处理器。
/**
* 自定义异常处理器,继承Exception或者RuntimeException,依情况而定.
* @author erqing
*
*/
public class NameNotSupportException extends RuntimeException { private static final long serialVersionUID = 7295869280641332966L; public NameNotSupportException() {
} public NameNotSupportException(String message) {
super(message);
}
}
public class DefineTest { public static void main(String[] args) {
String name = "egg";
if(!"erqing".equals(name)){
throw new NameNotSupportException("erqing");
}else{
System.out.println("name is OK!");
}
}
}
Exception in thread "main" NameNotSupportException: erqing
at DefineTest.main(DefineTest.java:7)
Java之Exception的更多相关文章
- JAVA基础 Exception, Error
转载请附上本文地址: http://www.cnblogs.com/nextbin/p/6219677.html 本文参考: JAVA源码 http://swiftlet.net/archives/9 ...
- java.lang.Exception: No runnable methods
java.lang.Exception: No runnable methods at org.junit.runners.BlockJUnit4ClassRunner.validateInstanc ...
- Java:Exception
异常: 就是程序在运行时出现不正常的情况. 异常的由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象.其实就是Java对不正常情况进行描述后的对象的体现. 两种 ...
- Error initializing endpoint java.lang.Exception: Socket bind failed: [730048] ?????????×???(Э?é/???????/???)????í??
2010-5-18 22:00:38 org.apache.catalina.core.AprLifecycleListener lifecycleEvent 信息: The Apache Tomca ...
- java.lang.Exception: Socket bind failed: [730013] An attempt was made to acc
在CMD命令行中启动运行startup.bat,启运程序总是闪退,查看日志发现如下错误: 26-Jan-2016 18:12:34.463 SEVERE [main] org.apache.coyot ...
- java.lang.Exception: Socket bind failed 服务器端口冲突-->修改端口
需要修改三个端口号:%apache_tomcat6%/conf/server.xml 四月 11, 2014 11:39:25 上午 org.apache.catalina.core.AprLifec ...
- java.lang.Exception: Socket bind failed: [730048] ?????????×???(Э?é/???????/???)????í??
严重: Error starting endpoint java.lang.Exception: Socket bind failed: [730048] ?????????×???(Э?é/???? ...
- Java常见Exception物种
Java常见Exception物种 1.ClassNotFoundException 2.IOException 3.NoSuchFieldException 4.NoSuchMethodExcept ...
- Java的Exception和Error面试题10问10答
在Java核心知识的面试中,你总能碰到关于 处理Exception和Error的面试题.Exception处理是Java应用开发中一个非常重要的方面,也是编写强健而稳定的Java程序的关键,这自然使它 ...
- 使用 JUnit 报错 java.lang.Exception: No runnable methods
错误详情如下: java.lang.Exception: No runnable methods at org.junit.runners.BlockJUnit4ClassRunner.validat ...
随机推荐
- 基站搭建与IMSI捕获
写在前面 : 实验目的是为了教学交流,坚决抵制违法行为. 一.实验目的 搭建基于OpenBTS的基站,手机接入该基站,进行短信.语音等测试. 二.所用仪器 USRP B210 1台,天线2根,PC机 ...
- Apache Tomcat 绿色版安装Service(服务)
1.配置CATALINA_HOME的环境变量: 变量名:CATALINA_HOME 值:tomcat安装或解压的根目录如:c:\Apache tomcat6.0 2.开始->运行->c ...
- Spring applicationContext爆出警告“Resource leak: 'applicationContext' is never closed”
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); 此处applicationCo ...
- 【Demo 1】基于object_detection API的行人检测 1:环境与依赖
环境 系统环境: win10.python3.6.tensorflow1.14.0.OpenCV3.8 IDE: Pycharm 2019.1.3.JupyterNotebook 依赖 安装objec ...
- PHP编码风格规范
由于PHP的灵活性,很多人写起代码来也不讲求一个好的代码规范,使得本就灵活的PHP代码看起来很乱,其实PSR规范中的PSR-1和PSR-2已经定义了在PHP编码中的一些规范,只要我们好好遵守这些规范, ...
- linux字符设备驱动中内核如何调用驱动入口函数 一点记录
/* 内核如何调用驱动入口函数 ? *//* 答: 使用module_init()函数,module_init()函数定义一个结构体,这个结构体里面有一个函数指针,指向first_drv_init() ...
- 浅谈 ASCII、Unicode、UTF-8,一目了然
对于ASCII.Unicode.UTF-8这三种编码方式我们经常用到,也经常挂到嘴边,但他们是怎么来的,为什么要存在,具体是怎么个规则,我们并没有做深入了解,下面,就带你看一下他们到底是怎么回事吧…… ...
- 链表:如何实现LRU缓存淘汰算法?
缓存淘汰策略: FIFO:先入先出策略 LFU:最少使用策略 LRU:最近最少使用策略 链表的数据结构: 可以看到,数组需要连续的内存空间,当内存空间充足但不连续时,也会申请失败触发GC,链表则可 ...
- Angular生命周期理解
Angular每个组件,包含根组件和每一级的子组件,都存在一个生命周期,从创建,变更到销毁.Angular提供组件生命周期钩子,把这些关键时刻暴露出来,赋予在这些关键结点和组件进行交互的能力. 在An ...
- c# 20160721
ctrl y =>反撤销 ctrl m m 隐藏当前代码段 重载运算符语法 把事件处理程序注册为 click事件的监听程序 [newButton.click+=newButton_click] ...