最近在做一个读取数据库元数据的框架,其中的数据库的检查异常让人印象深刻。try-catch简直让人抓狂,同时作为框架哪些异常时应该抛出来给调用人员,哪些是应该自己处理掉的,抛出来的异常时检查异常还是非检查异常都值得深思。下面很多仅仅是个人观点,希望大家补充和指出不对之处。

Java理念:结构不佳的代码不能运行。(泛型这点做的很差)

优点:1、用强制规定的形式来消除错误处理过程中随心所欲的因素;(C语言printf没人检查,scanf则会)。

2、能够降低错误处理代码的复杂度。(不需要太多的if-else)

3、携带信息,易于发现问题。(得益于强大的StackTrace栈轨迹)

什么是异常?

在当前环境下无法获取必要的信息来解决的,并且会影响当前方法或者作用域继续执行的问题。前面半句,你没法解决的问题,就交给你上一级来处理,所谓的抛出异常。如果你能解决的,你没解决,那就是你的程序有问题。下半句,无关紧要的异常,你可以处理掉(要留下信息),log4j找不到properties总不能让系统直接崩溃,就只这个理。

Try块的意义

方法内部抛出异常,这个方法就结束了(向更高层抛出)。如果你不希望结束,可以用try块。Try就是把可能抛出一样的方法集中处理。在没有异常处理的语言中,你可能需要不停的检查每个操作是否正确,在Java中可以集中处理。这对应的就是异常的优点2。

异常说明(检查异常的由来)

Java鼓励人们把方法可能抛出的异常告知使用此方法的客户端程序员。

Void f() throws TooBig,TooSmall,DivZero

说明方法f,有且只会抛出上面三个异常(RuntimeException除外)。Java认为这种种优雅的做法,但是也照成了很大的诟病。IO、数据库操作的时候,程序中会包含大量的异常处理。如果程序非常大,try-catch-finally简直就是灾难。

Spring jdbc中的JdbcTemplate把所有的数据库异常转换为DataAccessException异常,转换为一个Runtime异常。它进行二次封装的理由就是不需要用户关心特定数据库的细节,不需要强制用户使用try-catch。它在抛出的异常中,会把原来的信息给保存起来,即所谓的异常链。这非常重要,异常链对于调试的人员来说非常有用。Hibernate的SchemaExport就是一个糟糕的设计。

JdbcTemplate还阻止了一些不可能处理异常的抛出,如关闭数据库连接的异常,就算抛出给上层。上层通常也是无法处理的,还不如catch掉,然后用日志的形式输出。

使用心得或注意方式

1、  需要释放资源的,一定要放在finally里面。

  finally块中的代码是一定会被执行的。如果一下代码,在try中就有return,但是结束“照样”会输出。所以,当程序中包含数据库连接、IO、网络连接等需要释放资源的情况时,一定要使用finnally,避免不必要的消耗。

Int f(){

    try{

          return 0;
  }finally{
System.out.println(“结束”);
  }
}

在hibernate4.0版本以前,它就犯过资源没有释放的问题。

  在 Configuration.buildSessionFactory() 函数中:settings变量包含持有连接池的对象。获取的连接对象。如果SessionFactoryImpl创建异常,conn也将得不到释放。

2、  finally中绝不使用return与throw

finally里中如果抛出异常或者使用return,原本应该抛出的异常会丢失。如下所示,本意在f()中应该是要抛出Runtime异常的,不过在finnally中有了return就不再能捕捉到异常了。

static void f(){
try{ System.out.println("here"); throw new RuntimeException("my exception"); }finally{ return; } }
public static void main(String[] args) { f(); }

3、  如果要调用传入的参数的某个方法,一定要Null检查。或者该信息必不可少。

  如果不进行null检查,虚拟机也会帮你自动抛出runtime的NEP错误。所以,很多人并不在意这件事情。如果你的方法会被别人调用,且别人看不到你的方法代码,那问题就大了。

   static void f(String str){

      System.out.println(str.length());

   }
public static void main(String[] args) { f(null); }

  如上图的代码,抛出的异常信息显示,f方法中的第9行出现了NPE。但是,很可能别人调用你的代码时是已经编译过的class。在这种情况下,调用者就很难发现问题。所以,一定要进行异常检查,抛出一个新的并带有相关的提示信息。开源框架的代码都会进行这样的检查,如jdbcTemplate的某个方法,通过Assert.notNull对action进行了相关检查,如果为null抛出runtime异常。

4、  检查异常与非检查异常

Java的异常结构体系如下所示:

  其中的RuntimeException及其子类异常时非检查异常。在编程时不强制你显示处理。如果一个异常是致命的且不可恢复并且对于捕获该异常的方法根本不知如何处理时,或者捕获这类异常无任何益处,通常应该定义这类异常为非检查异常,由顶层专门的异常处理程序处理;像数据库连接错误、网络连接错误或者文件打不开等之类的异常一般均属于非检查异常。这类异常一般与外部环境相关,一旦出现,基本无法有效地处理。

  Spring Dao选择了把所有SQLException转换成了DataAccessException异常,是runtime的。这样,编程的代结构和可读性有了巨大的提升。如数据库关闭异常的,甚至直接catch并记录相关过程,连异常也不抛出。

  而对于一些具备可以回避异常或预料内可以恢复并存在相应的处理方法的异常,可以定义该类异常为检查异常。像一般由输入不合法数据引起的异常或者与业务相关的一些异常,基本上属于检查异常。当出现这类异常,一般可以经过有效处理或通过重试可以恢复正常状态。

5、  异常视角

使用者不应该接触Java异常,程序不应该在没有提示的情况下突然崩溃。Java像现在应用比较广泛的地方应是web方面。Tomcat之类的web容器能够很好的处理异常,一般情况内部的逻辑错误不会造成应用的崩溃。异常信息也会在前端页面显示,在开发阶段或者内部测试期间应该直接暴露异常信息至前端,这样有利于报告错误。正式发布阶段,应该将500等错误直接跳转至专门的页面。

6、  catch异常后冲洗throw异常,应该包含异常链

异常链对于程序调试尤为关键。异常链的保留可以追溯异常源,这样有利于异常的正确和及时定位。异常链的丢失,有的时候绝对是致命的。

参考: http://www.ibm.com/developerworks/cn/java/j-lo-exceptionframework/index.html?ca=dat

Java异常的优势与缺陷,及其处理原则的更多相关文章

  1. java异常面试题

    1.try{}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 也许你的答案是在return之前,但往更细地说, ...

  2. Java的最大优势还是跨平台么?

    之前码农界有码农说Java的最大优势是跨平台,真的是这样么?其实当时网络没这么火爆的时候,确实是这样的,但现在这已然不是了. 跨平台还是Java的最大优势么? 有跨平台需求的仅仅是客户端应用,而不是服 ...

  3. java异常——RuntimeException和User Define Exception

    1.RuntimeException public class RuntimeException { public static void main(String[] args) { // TODO ...

  4. JAVA异常设计原则

    异常是面向对象语言非常重要的一个特性,良好的异常设计对程序的可扩展性.可维护性.健壮性都起到至关重要. JAVA根据用处的不同,定义了两类异常     * Checked Exception: Exc ...

  5. Java 异常基础详解

    目录 1. Java 中的异常 1.1 什么是异常? 1.2 什么是异常处理? 1.2.1 异常处理的优势 1.3 Java 异常类的层次结构 1.4 异常类型 1.5 检查和未检查异常之间的区别 1 ...

  6. 【55】java异常机制剖析

    一.为什么要使用异常 首先我们可以明确一点就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率.虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位,作用.有异常就说明程序存在问题,有助于我们 ...

  7. Java基础10:全面解读Java异常

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  8. Java - 异常解析基础

    java提高篇(十六)-----异常(一) 一.为什么要使用异常 首先我们可以明确一点就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率.虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位 ...

  9. Java异常(三) 《Java Puzzles》中关于异常的几个谜题

    概要 本章介绍<Java Puzzles>中关于异常的几个谜题.这一章都是以代码为例,相比上一章看起来更有意思.内容包括:谜题1: 优柔寡断谜题2: 极端不可思议谜题3: 不受欢迎的宾客谜 ...

随机推荐

  1. 假设数组a有n个元素,元素取值范围是1~n,如何判定数组是否存在重复元素

    方法一:位图法,原理是首先申请一个长度为n且均为’0’组成的字符串,字符串的下标即为数组a[]中的元素,然后从头开始遍历数组a[N],取每个数组元素的值,将其对应的字符串中的对应位置置1,如果已经置过 ...

  2. 手机APP支付--整合银联支付控件

    长话短说,本文根据银联官方说明文档,简单总结下,并且说明下中途碰到问题该如何解决. 一.开发前的准备工作1. 打开https://open.unionpay.com/,后续说的文档下载.FAQ查询等都 ...

  3. luasocket 接收数据

    在游戏客户端使用luasocket作为网络通信的手段, 有一点很蛋疼, 就是它的receive是阻塞的,  那界面就卡死在那里了,  不过有一个函数:settimeout(), 传入参数0, 表示如果 ...

  4. 深入理解磁盘文件系统之inode

    一.inode是什么? 理解inode,要从文件储存说起. 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB). 操作系统 ...

  5. Druid连接池基本配置及监控配置

    1.配置Druid连接池,监控慢sql <!-- 数据源配置, 使用 Druid 数据库连接池 --> <bean name="dataSource" class ...

  6. osgearth缓存数据命令

    新建一个.bat文件 中国地区 osgearth_package.exe ReadyMap.earth --tms ReadyMap.earth --out D:\APICenter\EarthDat ...

  7. Maven编译出现“[ERROR] java.lang.OutOfMemoryError: Java heap space”

    Windows下添加环境变量MAVEN_OPTS的value为-Xms1024m -Xmx1024m -Xss1m Linux下可修改.profile或者.bash_profile文件,并做如下设置: ...

  8. 对C#中几个循环语句的使用,请教

    今天是在云和数据学院学习的第四天,由于各种原因···今天自己预习的循环语句的用法以及写了几个程序,也遇到各种的问题了···纠结.由于还是在学习的很初初初级,所以好多简单的方法还是不知道怎么写出来,只得 ...

  9. C++ template —— 智能指针(十二)

    在管理动态分配的内存时,一个最棘手的问题就是决定何时释放这些内存,而智能指针就是用来简化内存管理的编程方式.智能指针一般有独占和共享两种所有权模型.-------------------------- ...

  10. gcc的选项

    -g: 是一个编译选项,即在源代码编译的过程中起作用,让gcc把更多调试信息(也就包括符号信息)收集起来并将存放到最终的可执行文件内. -rdynamic:   却是一个 连接选项 ,它将指示连接器把 ...