最新JAVA编程实践.doc





《最新JAVA编程实践.doc》由会员分享,可在线阅读,更多相关《最新JAVA编程实践.doc(102页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、Four short words sum up what has lifted most successful individuals above the crowd: a little bit more.-author-dateJAVA编程实践OMC概要设计Soda模板JAVA编程实践1 引言本培训的主要目的是帮助被培训者了解如何使用JAVA语言构造出高效的、不易出错的、可维护的程序。同传统的程序设计语言相比,JAVA语言通过语法上的精心设计,例如通过引用替换指针,已经避免了很多使用C+或者其他语言容易导致错误的地方。但是,程序设计语言本身的语法本身并不能够保证程序正确无误,我们发现,即使程
2、序开发人员已经熟悉了JAVA语言的语法和函数库,要写出健壮的、高效的程序,也需要经过长时间的经验积累。使用同样的JAVA,要完成一个程序,可能会有10种编码方法,但是可能有7种都是低效的、笨拙的、可读性差、难以维护的编码方法。这是因为程序开发人员尽管已经掌握了语法规则和函数库,但是没有掌握正确的、高效的方式来编写代码。更为重要的是,开发人员有时候根本不知道什么是好的程序,什么是坏的程序,错误的使用一些技巧,使得程序复杂而且难以维护。我们通过在统一网管平台开发的实践,收集了一些最容易出错的编码问题,从中总结出一些编码的方式,这就是本次培训的目的。通过本次培训,我们希望能够帮助被培训者了解一些编码
3、中最可能出现错误的地方,写出简单的、高效的程序,使得程序更不容易出错,使得其他人能够更好的理解这些程序,也使得在发生错误的时候,你能够更快的找到错误的原因,在需要进行功能增强的时候,更容易的修改他们的程序。2 异常处理2.1 为什么要使用异常对于一个大型的软件系统,特别是那些需要连续运行几个月的服务器软件,错误处理通常会消耗程序员极大的精力。一个中等水平的程序员,一般说来都应该能够正确完成基本的事件处理流程,而对于错误处理,就很难考虑周全。我们经常看到,程序员能够很快的完成一个所谓演示系统,或者原型系统,或者他报告说已经完成了全部功能。但是,真正的要得到一个健壮的、稳定的商用软件,还需要花费程
4、序员很长的时间和精力。对于错误处理的估计不足,也是导致软件项目计划延期的重要原因。因此,有必要对错误处理加以特别的重视。在C、C+或者其他早期的语言中,通常采用返回值或者设置标志位的方式来处理错误。典型情况下,错误的发现函数设置一个错误码返回值/标志位,调用者检查这些返回值/标志位,判断发生的具体情况,并进行不同的处理流程。许多标准的C库函数也是采用这种方式来处理错误。这种方式使用了很多年,实际应用中发现了很多问题,其中最大的问题是,对于返回值的检查,不是依赖于语法来保证的,而是依赖于程序员的个人素质来保证的。程序员可以不检查这些错误的返回值/标志位,而在编译和运行期间,没有任何语法的措施来发
5、现这一点。通常,正确的处理流程只有一个,而发生错误的机会却非常之多,程序员也很难对全部的错误情况考虑周全。一种情况下,错误非常的隐蔽,程序员可能考虑不到。另一种情况下,错误非常的低级,程序员会产生麻痹情绪,这种错误如此愚蠢,怎么可能发生呢?所以就没有进行条件检查。即使程序员非常有经验,水平很高。但是,当函数调用层次很深的时候,如果在最下层的函数中发生了一个错误,上层的每一级调用者必须层层检查这些返回值。这样导致代码非常的庞大,也难以阅读,降低了软件的可维护性。有时候,一个服务器程序中,错误处理的代码要占到50%以上。我们发现,采用这种方式开发一个大型的、稳定的、又易于维护的系统,是一件非常困难
6、的事情。因此,JAVA中提供了异常处理机制,专门用于错误的处理。这种机制,将错误处理的方式作为程序设计语言的一部分,强制程序员进行错误处理。当发生异常的时候,程序员必须停下来,捕获该异常并进行处理,否则编译器就会报错:未捕获的异常。这样,就通过编译器保证了程序员必须处理错误。另一方面,异常处理机制使得错误处理的代码大大简化。编译器保证了一定会有一个地方来处理异常,这样,程序员不必层层检查返回值/标志位,而是只需要在“应该处理”的地方来处理错误。处理错误的代码和正常处理逻辑的代码很好的分离开,也有助于代码更加有条理易于维护。规则:使用异常处理机制来处理错误,而不是使用返回值或者标志位。2.2 基
7、本语法异常是一个较新的语法,很多程序员,特别是原来的C/C+程序员,没有完全掌握异常的语法,因此有必要在这里复习一下语法。2.2.1 throwthrow关键字用于“抛出”一个异常。使用该语句通常存在于两种情况:一种是抛出一个新的异常,一种是抛出一个已经存在的异常。如:2.2.2 throws对于一个提供其他方法调用的方法,需要告诉调用者该方法会抛出什么异常,这样,调用者才能够有针对性地进行错误控制。因此,JAVA引入了一个关键字:throws。该关键字用于方法声明,在该关键字后跟随所有的可能抛出的异常类型。假如一个方法中调用了另一个可能抛出异常的方法,那么一般情况下,该方法要么捕获这些异常,
8、并加以处理;要么也需要在自己的声明中throws这个异常。否则,编译器会报告一个错误。前面提到,异常处理机制和返回值/标志位处理方式的不同在于异常处理机制从语法上强制了程序员必须进行错误处理。这实际上表现为两个方面:首先,一个方法会发生什么错误,是在该方法的声明中通过throws语句告诉程序员的,而不是通过在注释中告诉程序员的。如果一个方法抛出了一个异常,又不在方法声明中写明,那么编译就无法通过。而编译器是无法控制是否在注释中写清楚返回值的含义的。其次,对于一个调用一个方法的程序员,他必须处理该异常,要么捕获,要么在继续向外抛出,否则编译也无法通过。2.2.3 try、catch & fina
9、llytry、catch、finally关键字用于捕获并处理异常。这里需要特别提到的是finally关键字。从语法上,在finally关键字作用范围之内的语句是正常和异常的处理流程中都需要执行的。一般情况下,这是指资源的释放。当申请一个资源之后,不论是否处理正确,处理完成之后,都必须释放该资源。将这些语句集中到finally语句块之中,有助于增加程序的可读性,并减少不释放资源的危险。在关于资源的培训中,将会有关于这一点的详细说明。2.3 异常分类2.3.1 java.lang.Throwable所有能够“throw”出来的对象的虚基类。实际应用中,应用不能够直接使用Throwable,也不能够
10、直接从它继承,而应该继承它的两个子类。2.3.2 java.lang.ErrorError表明严重的错误,通常当发生了这种错误的时候,程序已经无法在运行下去,只能够中断运行退出。应用程序不应该捕获并处理Error,这些工作应该由虚拟机完成。除了非常底层的程序之外,一般应用程序不需要继承Error,或者抛出Error。在公司的JAVA编程规范中,禁止直接从Error继承(可以从Error的子类继承)。2.3.3 java.lang.ExceptionException表明普通的错误,应用程序可以在程序中捕获这些异常并进行处理,保证程序能够继续运行。应用程序自定义的异常,都是Exception的子
11、类。我们在通常的情况下,处理的也都是这种类型的异常。2.3.4 java.lang.RuntimeExceptionRuntimeException是Exception的一种特殊子类,其特殊性在于:编译器不强制进行RuntimeException的处理。回顾2.2.2节,如果TestException是一个RuntimeException的子类,那么2.2节中的错误例子也能够通过编译器的检查。前面提到,异常处理机制的好处在于强制程序员进行异常处理。而如果使用了RuntimeException,则程序员可以完全不处理这些异常。这里JAVA为了编程的方便而提供了一些灵活性。那么RuntimeExc
12、eption一般应用于什么情况下呢?根据我的理解,RuntimeException用于表示这样一种异常:该异常只在调试期间产生,而在程序交付使用之后,根本不会出现的异常(好像名字正好取反了?)。导致该错误发生的原因是程序员的编程错误,而不是其他诸如通讯中断、磁盘错误、用户输入错误等。通常,一些公共函数库会抛出这类异常。看一个例子,假设有一个公共函数对于一个数组进行排序,参数为一个数组引用,如果传入的引用为一个空引用,那么该方法会抛出一个NullPointerException。这种错误会在什么时候产生呢?实际只有一种情况:调用该函数的程序写错了。也就是说,当调用程序调试正确之后,该异常永远不会
13、被抛出。上述的程序能够通过编译器的检查,但是会发生了一个NullPoinrtException,应用程序不进行处理,则这个异常会由JVM进行处理,从而中断正常的处理流程。这正好给程序员一个强烈的提示,此种情况表示了一个编程错误。当程序员的程序调试正确之后,这种情况就永远不会发生。注意,不需要自己检查NullPointerException。如以下的代码:2.4 finally的特别说明2.4.1 什么都逃不过finally的掌心我们看以下的代码:在代码中的3种情况,无论是自己抛出一个异常,还是直接返回,或者是产生一个NullPointerException,都逃不出finally语句。在代码中
14、发现一种情况,少数代码认为只要写finally,就必须写catch,结果导致了很多不必要的catch语句块。2.4.2 finally语句中不要抛出异常如果在finally语句中抛出异常,会掩盖真正需要抛出的异常,编程的时候特别需要注意这一点。假如在catch语句块和finally语句块中都抛出了异常,那么程序将不会抛出catch语句块中的异常,而是会抛出finally语句块中的异常。我们来看下面的例子:在以上的代码中,如果读写文件正常结束,执行到关闭文件的时候出了错,那么就会抛出异常,但是这种情况下,功能应该都完成了的,这会给客户端错误的信息。如果读写文件中发生异常,那么程序的原意是关闭文件
15、,将读写文件中发生的异常抛出。但是如果在关闭文件中,也发生了异常,那么最终抛出的是关闭文件的异常,而不是读写文件的异常。这就会给客户端程序错误的信息。而且调用者的到这个关闭异常之后,也无法判断文件的读写是否已经正常完成。2.5 Exception的特别说明2.5.1 是否需要捕获Exception在代码中常常发现,有些人为了确保程序正确,往往写一个catch(Exception ex),用这种方法来确保程序能够继续运行。其实这是不对的,因为这样实际上意味着写程序的人并没有认真地考虑可能发生的异常情况,写一个大而宽泛的catch(Exception ex),看起来很保险,实际上可能会掩盖很多编程
16、上的问题。因为我们在前面已经提过,实际上在Exception的所有子类中,除了RuntimeException之外,其他所有可能抛出的异常,如果你没有页:26catch,编译器都会发现并报错。而对于RuntimeException,我们认为是编程的错误,就是要让它暴露出来。当然,这也有一些例外情况,一个是在finally语句块中,因为不允许抛出异常,所以我们允许直接catch(Exception ex)。另一种情况是,为了确保程序在真正运行的时候不出问题,在线程的run方法中要捕获所有的异常进行处理,防止这个线程退出运行。因为实际上所有的代码都在线程中运行,只要控制住了这一点,就不会发生这些异
17、常影响程序运行的现象发生。问题:出现异常的情况下,我需要释放资源,如果不捕获RuntimeException,不会出现资源不被释放的情况发生吗?2.5.2 不要在函数声明中throws Exception前面提到,不要捕获Exception,那么如果在函数的声明中写throws Exception,就强迫了使用者要catch Exception。所以,在函数声明中,一定要写清楚throws的具体的异常类。2.6 如何定义异常2.6.1 异常的层次和异常链如果高层方法调用了低层方法,在低层方法中抛出了一个异常,如果高层方法中不加处理的抛出该异常,那么对于该方法的使用者来说,可能会感到无法理解。因
18、为高层方法的使用者为了理解这个异常,就必须了解高层方法的实现细节。假如高层方法的实现发生改变,就有可能导致抛出的异常发生变化,从而导致需要修改高层方法的客户端程序,因为需要捕获的异常发生变化了。为了避免这种情况发生,高层方法应该自己捕获低层方法的异常,将其转换成为按照高层解释的新的异常。这种方法称为异常转换。也就是说,抛出的异常语意应该和方法的语意层次相一致。例如,一个处理某项业务逻辑的方法,目前该方法实现中使用文件作数据存储,但是未来有可能改变为使用数据库做数据存储。那么该方法抛出的异常,其语意应该表明数据存储失败,而不是文件操作失败。否则,现在客户端程序捕获处理文件操作失败异常,当方法实现
19、改为数据库时,客户端程序必须修改为捕获数据库操作失败异常。进行了异常转换之后,为了能够在调试程序的时候,能够追根溯源到异常的原始发生地,那么需要在高层异常中保留低层异常。高层异常中保留了低层异常,低层异常中又保留了更低层的异常,这种情况称为异常链。JAVA的Exception类提供了对于异常链的支持:Constructor SummaryException() Constructs a new exception with null as its detail message.Exception(Stringmessage) Constructs a new exception with th
20、e specified detail message.Exception(Stringmessage, Throwablecause) Constructs a new exception with the specified detail message and cause.Exception(Throwablecause) Constructs a new exception with the specified cause and a detail message of (cause=null ? null : cause.toString() (which typically cont
21、ains the class and detail message of cause).使用了以上3、4的构造方法的时候,当打印异常堆栈的时候,会把cause也一起打印出来,如:java.lang.Exception: aaaat zq.sample.TestExceptionChain.openFile2(TestExceptionChain.java:40)at zq.sample.TestExceptionChain.main(TestExceptionChain.java:47)Caused by: java.io.FileNotFoundException: aaa (系统找不到指定
22、的文件。)at java.io.FileInputStream.open(Native Method)at java.io.FileInputStream.(FileInputStream.java:103)at java.io.FileInputStream.(FileInputStream.java:66)at zq.sample.TestExceptionChain.openFile1(TestExceptionChain.java:22)at zq.sample.TestExceptionChain.openFile2(TestExceptionChain.java:37)2.6.2
23、我们系统的情况对于统一网管平台,我们将程序分为两类:公共函数,和应用程序。这两类程序的层次不同,抛出的异常类型所属的层次不一样。在平台中,一般只需要两层异常层次就可以了,低层异常由公共函数抛出,我们称为原始异常;高层异常由处理业务逻辑的应用程序抛出,称为应用异常。应用程序捕获原始异常,将其转换成为应用异常。公共函数提供一系列函数库,供其它程序使用。对于这一类函数,抛出的原始异常包括两类:RuntimeException。这些异常主要是由于调用者的程序书写不当造成的。由于JDK已经定义了绝大多数由编程错误导致的异常,所以写函数库的程序员一般情况下不需要自定义异常类型,只需要直接使用JAVA已经定
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 最新 JAVA 编程 实践

限制150内