1.提倡异常封装
Java语言的异常处理机制可以确保程序的健壮性,提供系统的可用率,但异常的API通常是比较"低级" 什么是低级别?那就是不包含业务的,只是程序员才能看懂的异常信息,而对于用户来说,基本就是看天书,什么是NullPointException?这些都是纯计算机语言的描述,而对于用户而言是需要业务级别的异常信息,所以我们提倡对异常的封装,异常封装有3个优势
1.提高系统的友好性,由于系统提供的异常都是低级的,例如打开一个文件,如果文件不存在,则会报出FileNotFoundException,此时若然我们不对异常进行封装直接将栈信息输出到用户端,那用户根本就不知道是什么意思,我们应该对异常进行业务性的说明,例如提示文件不存在等.
2.提高系统的可维护性,我们很多时候喜欢将多个异常信息直接使用一个异常的父类Exception或RuntimeException来表达,这种做法是不推荐的,就算将异常栈信息输出,维护人员还是要追寻到代码的层面才可以定位到异常发生的地方,这对系统的维护性造成了很大的影响,我们应该分开编写异常信息.
3.解决Java异常机制自身的缺憾,Java当中的只要代码触发异常,就会跳到这个异常对应的catch块当中处理,而忽略其他catch块,这对于单独的一个代码块是没有问题的,但若然是多个代码块或一个链式的处理,链当中可能多一个节触发了异常,但我们最终是会看到一个异常,所以使用异常封装就能实现记录多个异常信息,请观察以下代码
- public class MyException extends RuntimeException {
- private static final long serialVersionUID = 701064983280219053L;
- private List<Throwable> exceptionList = new ArrayList<Throwable>();
- public MyException(List<? extends Throwable> cause) {
- this.exceptionList.addAll(cause);
- }
- // 调用时
- public static void main(String[] args) {
- List<Throwable> exceptionList = new ArrayList<Throwable>();
- // 第一代码片段
- try {
- } catch (Exception e) {
- exceptionList.add(e);
- }
- // 第二代码片段
- try {
- } catch (Exception e) {
- exceptionList.add(e);
- }
- // 第三代码片段
- try {
- } catch (Exception e) {
- exceptionList.add(e);
- }
- // 正式抛出异常
- if (exceptionList.size() > 0) {
- throw new MyException(exceptionList);
- }
- }
- }
2.采用异常链传递异常
我们的JavaEE项目一般是三层结构,持久层,逻辑层,展现层,持久层是负责读取数据的,例如我们现在需要加载一个文件作为数据,但此时报出FileNotFoundException,由于该异常是检查性异常,所以必须在持久层处理或往上抛,但此时若然使用上抛的方式,逻辑层在调用时基本无法知道持久层为什么会出现这个错误,这个错误应该是持久层最清楚的,所以我们应该把异常封装好后传递到逻辑层,请观察以下代码
- public void test() {
- File file = new File("/test.xml");
- try {
- FileInputStream fis = new FileInputStream(file);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- throw new MyException("文件不存在", e);
- }
- }
在持久层封装好自定义的异常类信息后抛出到逻辑层中,逻辑层到展现层亦同理
3.检查性异常尽量转化为非检查性异常
把所有检查性异常(Checked Exception)都转换为非检查性异常(UncheckedException)是不现实的,因为检查性异常是正常逻辑的一种补充处理手段,在某些条件下必须抛出检查性异常以便上层为底层的错误进行处理,那为什么非要把受检异常转换为非受检异常呢?
1.检查性异常使接口声明脆弱我们应该面向接口编程,但由于检查性异常大多需要抛出,这就使得在声明接口的时候,需要把抛出的异常类型也一并声明,若然在开发迭代的过程中发现实现类需要抛出更多的异常,那我们就必须要修改接口,这就是类影响接口的情景,其实我们可以看出,在很多著名的框架当中,都在使用着非检查性异常,例如Hibernate,Spring等,特别是Hibernate框架,把底层的JDBC检查性异SQLException全部隐藏了起来而只使用了Hibernate定义的非检查性异常.
2.检查性异常使代码可读性降低当我们逻辑层调用持久层时,若然抛出了检查性异常,我们的逻辑层必须要对其进行try catch处理,或者再往展现层抛出,这样对持久层的调用者来说意味着,每次调用持久层的方法都需要增加4行代码才能成功调用,这样大大降低了代码的可读性
3.受检异常增加了开发工作量我们从上面所述可以知道,我们推荐对异常进行封装,上层模块才能更好的处理和显示给用户,但这也导致了底层没完没了的封装,无疑是加重了开发的工作量,但在软件当中,几乎是不存在完美的解决方案,就例如数据库设计中的容量换效率和效率换容量一样,我们只能取其平衡的地方,适当的对异常进行封装
检查性异常有如此多的缺点,所以我们在开发当中通常会将检查性异常转换为非检查性异常,检查性异常的父类为Exception,非检查性的异常父类为RuntimeException,只要我们封装的异常类型是继承RuntimeException就可以抛出非检查性异常,检查性异常提出的是“法律下的自由”,而非检查性异常则是“约定的自由”
4.在使用日志框架时需要注意异常吞噬
使用开源日志框架,例如log4j等已经在项目当中广泛的使用,请留意以下代码
- public class Test {
- Logger logger = LoggerFactory.getLogger(this.getClass());
- public void test() {
- try {
- } catch (Exception e) {
- e.printStackTrace();
- logger.warn("错误信息", e.getMessage());
- new MyException("错误信息", e);
- }
- }
- }
以上代码是使用日志框架对检查性异常时的公认写法,有项目维护或开发经验的人知道,在项目维护阶段出现错误时,通常客户会将日志文件发送给维护人员,然后维护人员根据日志文件中的错误定位程序进行修复,而不是将在控制台的信息直接复制给维护人员,读者要分清控制台输出和日志文件的概念,printStackTrace方法是将错误的栈信息输出到控制台中,若然此时我们没有使用logger对异常信息进行记录,那我们将会把此异常信息吞噬掉,导致定位错误时将一头雾水,当然项目可能会设置将控制台的信息一并记录到日志文件中,但在开发阶段,我们应该尽量避免这种不稳定的事情发生.
5.不要在finally中处理返回值
在finllay中处理返回值,是考试和面试题中经常出现的题目,但请谨记,在项目当中绝对不要在finally中处理返回值,请留意以下代码
- public static int doSomething(int num) throws Exception {
- try {
- if (num < 0) {
- throw new Exception("error");
- }else{
- return num;
- }
- } catch (Exception e) {
- throw e;
- } finally {
- return -1;
- }
- }
- public static void main(String[] args) {
- try {
- doSomething(-1);
- doSomething(100);
- } catch (Exception e) {
- System.out.println("永远不会到达");
- }
- }
我们都知道无论是否触发异常运行catch块,finally都会被执行,以上的答案两个结果都返回为-1,而且调用该方法不会抛出异常,而且覆盖了try中的返回值,而且告诉了JVM,我这个方法调用正常返回,没有问题,屏蔽了异常,在Eclipse等IDE中若在finally增加返回值还会提示警告信息,所以切记finally中不要出现返回值,finally应该作释放资源用
6.不要在构造函数中抛出异常
我们知道类的创建会执行构造函数,其实从语法层面来说完全可以在构造函数中抛出异常,但从系统设计角度来说,尽量不要在构造函数中抛出异常,这样的行为不仅使子类扩展父类的构造函数受到限制,而且也违背了里氏替换原则,除非该类不应该被创建或不想被反射技术创建,则应该在构造函数增加异常
7.使用Throwable获取栈信息
如何做到对同一个方法(同参数)的调用返回两个不同的结果?请观察以下代码
- public static boolean doSomething(){
- StackTraceElement[] stes = new Throwable().getStackTrace();
- for(StackTraceElement ste : stes){
- if(ste.getMethodName().equals("test")){
- return true;
- }
- }
- throw new RuntimeException("除test方法外,我不允许其他人调用");
- }
- public static void test(){
- doSomething();
- }
- public static void test1(){
- //我报错了
- doSomething();
- }
这里对同一个方法调用,产生了两种结果,为什么呢?因为在创建一个Throwable类时,JVM会记录下栈信息,然后生成Throwable对象,这样我们就可以知道类之间调用的顺序,方法名称和当前行号等等,就可以完成只要调用者不是test方法,就产生错误
8.异常只为异常服务
异常原本的用意是正常逻辑的一个补充,有时甚至会被当做业务主体来使用,就例如在finally和catch中增加业务代码,但这种做法是不推荐的,导致代码产生了坏味道,所以并不推荐在异常中做过多的业务逻辑处理,除非必须,否者应该尽量避免
9.多使用异常作为信息
由于我们的应用大多是三层架构,若然不使用异常进行信息的封装传递,我们就必须定义记录信息的变量在三层中互相传递,这样的做法降低了对代码的可读性,而且忽视了Java本身提供的信息传递途径,而在持久层通过异常的封装传递到展现层,最终显示给用户,通过异常类这个载体,可以很好的完成这项工作,例如Struts2都提供了标签让我们更好的输出异常中的信息,更提供了'值栈'给我们,使用<s:debug />看一下,你会看到Exception在里面
相关推荐
Java异常处理是编程中至关重要的一个环节,它帮助开发者识别并修复程序运行时出现的问题。在Java中,异常是程序执行期间发生的不正常情况,通常会导致程序中断。下面将详细解释给定文件中提到的一些常见Java异常,并...
Java异常框架是Java编程语言中处理程序运行时错误和异常的核心机制。在Java中,异常是一种特殊的对象,用于表示程序运行过程中的不正常状态。Java的异常处理模型基于\"异常处理块\",包括try、catch、finally和throw...
综上所述,"java转js工具"是一个重要的开发辅助工具,它帮助开发者在Java和JavaScript之间架起桥梁,使得跨平台开发变得更加便捷。然而,使用时需要注意语言特性的差异,以及转换过程中可能出现的问题和挑战。
在Java编程语言中,`NumberFormatException`是一个常见的运行时异常,它发生在尝试将字符串转换为特定数字类型(如`Integer`, `Double`, `Float`等)时,如果字符串不能被解析为对应类型的数值,就会抛出这个异常。...
Java异常处理的9个最佳实践涵盖了开发者在进行Java编程时应当遵循的一系列规则和方法,以确保代码的健壮性和可维护性。异常处理是编程中的一个重要部分,它能够帮助我们更有效地管理和响应程序运行时的错误情况。 ...
4. 异常处理:Java的try-catch-finally在Python中对应于try-except-finally结构,转换时需要注意异常类型的映射。 5. 数组与列表:Java的数组在Python中通常对应为列表,但Java数组是固定大小的,而Python列表可以...
### Java异常处理机制详解与案例分析 在Java编程语言中,异常处理是程序设计中一个非常重要的组成部分。它能够帮助开发者有效地捕捉并处理程序运行时出现的问题,避免因错误而导致程序崩溃,从而提高软件的健壮性和...
Java异常处理是编程中至关重要的一个环节,它允许程序员优雅地处理程序运行过程中可能出现的错误情况,确保程序的稳定性和健壮性。异常处理机制在Java中被设计为一种结构化的方法,使得程序在遇到不可预见的问题时,...
以下是对Java异常处理的一些误区和经验总结。 **误区一:过度使用try-catch块** 有些开发者习惯于在每个函数的开始部分都套用try-catch块,以为这样可以捕捉所有可能出现的异常。实际上,这种做法使得代码变得混乱...
在Java开发中,有时我们需要将Word文档转换为PDF格式,以满足不同的应用场景需求。...通过正确的依赖配置和代码实现,你就可以避免描述中提到的运行时异常,成功地在Java项目中实现Word到PDF的转换了。
Java转C++代码工具J2C是一个专门用于将Java源代码转换为等效C++代码的工具。这个工具对于那些需要在不支持Java或者需要利用C++特定性能特性的环境中迁移Java项目的人来说非常有用。在深入探讨J2C之前,我们先理解...
"java行转列"这个主题是数据处理中的一个常见需求,尤其是在数据分析、报表生成或数据显示时。当我们从数据库中获取数据,有时会遇到单个字段的数据需要在用户界面上以列的形式展示,这时就需要进行数据的行列转换。...
为了更好地理解和处理这些异常,本文将详细介绍几种常见的Java异常类型及其处理方法。 #### 1. `java.lang.NullPointerException` - **异常概述**:`NullPointerException`是Java中最常见的运行时异常之一,它发生...
Java异常处理是编程过程中的重要组成部分,它帮助开发者在程序执行期间识别并处理错误和意外情况。Java异常是程序运行时出现的不正常状态,它们通常由Java虚拟机(JVM)或者Java类库在遇到特定问题时抛出。异常分为...
3. **异常处理**:Java 使用 try-catch-finally 结构处理异常,而 VB 和 VC 使用 Try...Catch...Finally 或 Select Case...Of 语句。转换工具需要理解这些差异并进行相应转换。 4. **标准库和API**:Java 标准库...
`JAVA wav转PCM Utils代码工具类`提供了这样的功能,使得开发者能够便捷地进行音频格式的转换。以下是对这个工具类的详细说明: ### WAV格式 WAV是一种无损音频文件格式,由Microsoft开发,广泛用于Windows平台。它...
这个过程涉及到类、方法、变量、条件语句、循环、异常处理等众多语法元素的转换。由于Java和Pascal的语法差异,转换过程中可能会遇到一些挑战,比如Java中的匿名内部类在Pascal中可能需要不同的表示方式,或者Java的...
值得注意的是,这个过程中可能会遇到编码问题、样式丢失、图片无法显示等问题,因此实际应用时可能需要更复杂的处理逻辑,比如处理CSS、JavaScript等,以及对异常的妥善处理。 总结一下,Java中将URL转换为PDF涉及...