Java语法总结 - 异常
软件开发中一个古老的说法是:80%的工作使用20%的时间。80%是指检查和处理错误所付出的努力。在许多语言中,编写检查和处理错误的程序代码很乏味,并使应用程序代码变得冗长。原因之一就是它们的错误处理方式不是语言的一部分。尽管如此,错误检测和处理仍然是任何健壮应用程序最重要的组成部分。
Java提供了一种很好的机制,用强制规定的形式来消除错误处理过程中随心所欲的因素:异常处理。它的优秀之处在于不用编写特殊代码检测返回值就能很容易地检测错误。而且它让我们把异常处理代码明确地与异常产生代码分开,代码变得更有条理。异常处理也是Java中唯一正式的错误报告机制。
第一部分 异常
1、抛出异常。所有的标准异常类都有两个构造器:一个是缺省构造器,一个是带参数的构造器,以便把相关信息放入异常对象中。
throw new NullPointerException();
throw new NullPointerException("t = null");
2、如果有一个或者多个catch块,则它们必须紧跟在try块之后,而且这些catch块必须互相紧跟着,不能有其他任何代码。C++没有这样的限制,所以C++的异常处理处理不好就会写得很乱,抛来拋去的。
3、使用try块把可能出现异常的代码包含在其中,这么做的好处是:处理某种指定的异常的代码,只需编写一次。作业没写完的同学到走廊罚站去,这符合我们处理问题的方式,不用挨个地告诉。
4、无论是否抛出异常,finally块封装的代码总能够在try块之后的某点执行。
例子:
try {
return ;
}
finally{
System.out.print("You can't jump out of my hand!");
}
甚至你在try块内用return语句想跳过去都不可以!finally内的输出语句还是执行了!别想逃出我的手掌心!
5、catch块和finally块是可选的,你可以只使用try。但是这么做有意思吗?
6、推卸责任。Java允许你推卸责任,没有必要从相应的try块为每个可能的异常都编写catch子句。Java2类库中很多方法都会抛出异常,就是是把异常处理的权限交给了我们用户。毕竟,Java不知道你的自行车被偷了之后,你会去报案还是会忍气吞声自认倒霉,或者偷别人的自行车。我们需要这种处理异常的自由度。
7、调用栈。调用栈是程序执行以访问当前方法的方法链。被调用的最后一个方法在栈的顶部,它将被最先执行完毕,然后弹出;第一个调用方法位于底部,也就是main函数。在catch子句中使用printStackTrace()方法打调用栈信息是比较常用的定位异常的方法。printStackTrace()继承自Throwable。
8、异常的传播。在一个方法A中,如果一个异常没有得到处理,它就会被自动抛到调用A方法的B方法中。如果B方法也没有处理这个异常,他就会被继续依次向上抛,直到main方法。如果main也没有理会它,那么异常将导致JVM停止,程序就中止了。你被同学揍了,先去告诉老师。老师不理你你就去告诉教导处主任,教导处主任也不管那只能告诉校长,校长还不管!没有比他更大的了,于是你崩溃了,学业中止了……下面这段程序记录了悲惨的辍学历史:
class ExceptionDemo {
static void student() throws Exception{
teacher();
}
static void teacher() throws Exception{
schoolmaster();
}
static void schoolmaster() throws Exception{
throw new Exception();
}
public static void main(String[] args) {
try {
student();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果是:
java.lang.Exception
at ExceptionDemo.schoolmaster(ExceptionDemo.java:9)
at ExceptionDemo.teacher(ExceptionDemo.java:6)
at ExceptionDemo.student(ExceptionDemo.java:3)
at ExceptionDemo.main(ExceptionDemo.java:13)
可以看出函数的调用栈,一级一级地哭诉……
9、异常的层次结构及Error。
Object
Throwable
Error Exception
Throwable继承自Object,Error和Exception继承自Throwable。Error比较特殊,它对应于我们常说的不可抗拒的外力,房屋中介的合同上总有一条,如遇不可抗拒的外力本合同中止,返还乙方押金。我不安地问:不可抗拒的外力指什么?中介回答:比如战争、彗星撞击地球等。对Java来说Error是指JVM内存耗尽等这类不是程序错误或者其他事情引起的特殊情况。一般地,程序不能从Error中恢复,因此你可以能眼睁睁地看着程序崩溃而不必责怪自己。严格来讲,Error不是异常,因为它不是继承自Exception。
10、谁之错?一般地,异常不是我们程序员的错,不是程序设计上的缺陷。比如读取一个重要文件,这个文件被用户误删了;正上着网呢,网线被用户的宠物咬断了。为了程序的健壮性,我们尽量考虑出现可能性大的异常,并处理,但我们不能穷尽。
11、异常的捕获之一。catch子句的参数是某种类型异常的对象,如果抛出的异常是该参数的子类,那么这个异常将被它捕获。也就是说被抛出的异常不会精确地寻找最匹配的捕获者(catch子句),只要是它的继承结构的直系上层就可以捕获它。
按照这个逻辑,catch(Exception e) 不就能捕获所有的异常吗?事实上,确实如此。 但是一般地,不建议使用这种一站式的异常处理。因为这样就丢失了具体的异常信息,不能为某个具体的异常编写相应的异常处理代码,失去了异常处理的意义。从哲学角度来讲,具体问题要具体分析,能治百病的万能药一般都是无效的保健品。
Java在此处为什么这么设计呢?因为有另一种机制的存在,请看下条分解。
12、异常的捕获之二。当抛出一个异常时,Java试图寻找一个能捕获它的catch子句,如果没找到就会沿着栈向下传播。这个过程就是异常匹配。Java规定:最具体的异常处理程序必须总是放在更普通异常处理程序的前面。这条规定再合理不过了,试想如果把catch(Exception e)放在最上面,那么下面的catch子句岂不是永远不能执行了?如果你非要把更普遍的异常处理放在前面,对不起,通不过编译!虽然编译器不会这样报错:“It is so stupid to do like that!”……
13、捕获或声明规则。如果在一个方法中抛出异常,你有两个选择:要么用catch子句捕获所有的异常,要么在方法中声明将要抛出的异常,否则编译器不会让你得逞的。
方案一:处理异常
void ex(){
try{
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
方案二:抛出去
void ex() throws Exception{
throw new Exception();
}
比较一下行数就知道了,在代码的世界里推卸责任也是那么简单,一个throws关键字包含了多少人生哲理啊……现实生活中我们有很多角色,儿女、父母、学生、老师、老板、员工……每个人都占了几条。可是你能尽到所有责任吗?按照古代的孝道,父母尚在人世就不能远行。各种责任是有矛盾的,顾此失彼啊。
但是这条规则有个特例。一个继承自Exception名为RuntimeException的子类,也就是运行时异常,不受上述规则的限制。下面的代码完全能编译,只不过调用之后在运行时会抛出异常。
void ex(){
throw new RuntimeException();
}
14、throw和thrwos关键字。throw用在方法体中抛出异常,后面是一个具体的异常对象。throws用在方法参数列表括号的后面,用来声明此方法会抛出的异常种类,后面跟着一个异常类。
15、非检查异常。RuntimeException、Error以及它们的子类都是非检查异常,不要求定义或处理非检查异常。Java2类库中有很多方法抛出检查异常,因此会常常编写异常处理程序来处理不是你编写的方法产生的异常。这种机制强制开发人员处理错误,使得Java程序更加健壮,安全。
16、自定义异常类型。觉得现有的异常无法描述你想抛出的异常,ok!Java允许你自定义异常类型,只需要继承Exception或者它的子类,然后换上有个性的名字。
class NotEnoughMoney extends Exception {
public NotEnoughMoney() {}
public NotEnoughMoney(String msg) { super(msg); }
}
希望大家在生活里不要抛出类似的异常。
17、重新抛出异常。一个很无聊的话题,纯粹的语法研究,实际意义不大。当catch子句捕获到异常之后可以重新抛出,那么它所在的方法必须声明该异常。
void ex() throws Exception{
try {
throw new Exception();
}
catch (Exception mex) {
throw me;
}
}
18、异常处理机制的效率。待补充……
19、终止与恢复模型。异常处理理论上有两种模型:
一、终止模型。错误很关键且无法挽回,再执行下去也没意义,只能中止。“罗密欧,我们分手吧!”“好吧,朱丽叶!”
二、恢复模型。经过错误修正重新尝试调用原来出问题的方法。“罗密欧,我们分手吧!”“朱丽叶,我错了!请再原谅我一次吧!”“好的,再原谅你最后一次!”
显然我们更喜欢恢复模型,但在实际中,这种模式是不易实现和维护的。
例子:用户输入了非法的字符,分别按照两种模式处理
一、终止模型。输出出错信息而已,一旦用户手一抖眼一花你的代码就崩溃了
double number;
String sNumber = "";
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
sNumber = bf.readLine();
number = Double.parseDouble(sNumber);
} catch (IOException ioe) {
System.err.println("some IOException");
} catch (NumberFormatException nfe) {
System.err.println(sNumber + " is Not a legal number!");
}
//System.out.println(number);
二、恢复模型。小样!不输入正确的数据类型就别想离开!
double number = 0;
String sNumber = "";
while(true){
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
sNumber = bf.readLine();
number = Double.parseDouble(sNumber);
break; //如果代码能执行到这一行,就说明没有抛出异常
} catch (IOException ioe) {
System.err.println("some IOException");
} catch (NumberFormatException nfe) {
System.err.println(sNumber + " is Not a legal number!");
}
}
System.out.println(number);
直到用户输入正确的信息才会被该代码放过。这是一种简单的恢复模型的实现,挺耐看的,我很喜欢!
20、try、catch、finally内变量的作用域和可见性。
在try块内定义的变量,它在catch或者finally块内都是无法访问到的,并且在整个异常处理语句之外也是不可见的。
补充一点初始化:第一个例中最后一句被注释掉了。number是在运行时由用户输入而初始化的,但是在编译时刻并没有初始化,编译器会抱怨的。
21、输出异常信息。捕捉到异常之后,通常我们会输出相关的信息,以便更加明确异常。
catch (Exception mex) {
System.err.println("caught a exception!");
}
用标准错误流System.err比System.out要好。因为System.out也许会被重定向,System.err则不会。
22、更高级的话题我会补充上的,但是我的肚子抛出了Hungry异常,我必须catch然后调用eat()方法补充能量。昨晚的鱿鱼盖浇饭很好吃……
分享到:
相关推荐
《深入浅出MFC》是一本专为C++程序员深入理解Microsoft Foundation Classes (MFC) 库而编写的经典教程。MFC是微软提供的一套C++类库,用于简化Windows应用程序开发,它将Windows API封装成易于使用的C++类。这本书的...
《深入浅出C#》是一本专为C#初学者设计的编程教程,它以其深入浅出的讲解方式,帮助读者快速掌握C#这门强大的编程语言。C#是由微软公司开发的一种面向对象的编程语言,广泛应用于Windows平台、Web应用、游戏开发等多...
《深入浅出ARM7》是周立功先生撰写的一本关于ARM微处理器体系结构和技术的专著,这本书深入解析了ARM7处理器的工作原理及其在嵌入式系统中的应用。ARM7是ARM公司早期设计的一种高性能、低功耗的32位RISC(精简指令集...
《深入浅出C#》是HeadFirst系列中的一本经典编程教材,专为初学者设计,采用独特的视觉和认知教学法,旨在帮助读者快速、轻松地掌握C#语言的核心概念。该书的前四章涵盖了C#编程的基础,是学习C#之旅的重要起点。 ...
SVM在处理小样本、非线性以及高维数据时展现出独特的优势,并且能够应用于函数拟合等多种机器学习问题。 #### 二、SVM原理 ##### 1. 基础理论背景 - **统计学习理论与VC维理论** - **统计学习理论**:由Vapnik...
《C#深入浅出全接触》是一本专为C#编程爱好者和专业开发人员精心编写的书籍,旨在帮助读者全面理解和掌握C#编程语言的核心概念和技术。C#(读作"C sharp")是由微软公司推出的面向对象的编程语言,广泛应用于Windows...
《深入浅出Java》这本书以其独特的讲解方式,旨在让学习者轻松掌握复杂的Java编程语言。"深入浅出"这一理念,意味着作者通过直观、生动的示例和丰富的图解,帮助读者逐步理解Java的核心概念和技术。 Java是一种广泛...
《深入浅出ARM7》这本书,不仅仅为读者提供了对ARM7硬件和软件的全面介绍,更是嵌入式系统开发者的实践宝典。正如其标题所示,本书的编排既涵盖了基础知识点,也触及了深入的技术细节,旨在帮助读者从多方面深入理解...
9. **教学视频**:侯捷老师的教学视频无疑是光盘中的亮点,他以其深入浅出的讲解方式,帮助读者理解抽象的概念和技术难点,通过视频学习可以更直观地看到代码运行效果和调试过程。 通过学习《深入浅出MFC》随书光盘...
这本书以其深入浅出的讲解方式,引领读者步入MFC的世界,让开发者能够更高效地构建Windows桌面应用。 书中的内容可能涵盖以下几个关键知识点: 1. **MFC基础**:首先介绍MFC的基本概念,包括类库的结构、类的层次...
《深入浅出MFC》是C++编程领域中一本经典的MFC(Microsoft Foundation Classes)教程,作者侯捷,以其深入浅出的讲解方式深受程序员喜爱。MFC是微软为Windows平台提供的一套类库,它封装了Windows API,使得开发者...
《深入浅出WINCC》是一本专为学习和掌握SIMATIC WinCC自动化系统设计的教程。SIMATIC WinCC是西门子推出的一款强大的人机界面(HMI)软件,广泛应用于工业自动化领域的监控与数据采集。这本书以清晰易懂的方式,帮助...
《深入浅出MFC》是一本专为程序员深入理解Microsoft Foundation Classes (MFC) 库设计的书籍。MFC是微软公司开发的一个C++类库,它为Windows应用程序开发提供了强大的支持,使得开发者能够更容易地利用Windows API...
WinCC的主要功能和组态方法是本书《深入浅出WinCC》的主要内容,本书分为基础篇和高级篇两大部分,旨在帮助读者系统学习WinCC V6.0的相关知识。 基础篇主要介绍了WinCC的以下几方面应用: 1. 变量记录系统:这部分...
《深入浅出Cortex-M3——LPC178x.177上下册》是一部由周工编著的专业书籍,旨在深入解析ARM Cortex-M3处理器及其在LPC178x/177x系列微控制器中的应用。Cortex-M3是ARM公司设计的一种高效能、低功耗的32位微控制器...
这本书的"深入浅出"系列教材以其深入浅出的讲解方式,深受程序员喜爱,被誉为学习MFC的绝佳参考资料。 MFC的主要功能包括窗口管理、消息处理、文档/视图架构、数据库访问、网络编程等。通过阅读《深入浅出MFC》,...
《Python深入浅出》这本书是Python编程学习者的宝贵资源,旨在帮助读者全面理解Python语言的精髓,提升编程技能。本书涵盖了Python的基础语法、高级特性、数据结构、面向对象编程、函数式编程、错误与异常处理、模块...
根据提供的信息,《竹林蹊径 深入浅出Windows驱动开发》这本书主要讲述了Windows操作系统下的驱动程序开发技术。本书作者张佩等人以其丰富的实践经验和技术积累为基础,为读者提供了深入浅出的学习指南,旨在帮助...
总之,“深入浅出Struts2”这份资料全面讲解了Struts2的各个关键组成部分,包括其工作原理、配置方式、拦截器机制、OGNL表达式、插件使用以及与Spring的整合,是学习和掌握Struts2框架的宝贵资源。通过深入学习和...
《深入浅出LPC2300》是一本专注于ARM微处理器系列的优秀学习资源,主要针对NXP公司的LPC2300系列芯片进行详细讲解。ARM处理器因其高效能和低功耗特性,在嵌入式系统领域广泛应用,是许多电子设备的核心组件。LPC2300...