在 Java 中,因为 JDBC 很多函数都抛出 SQLException,程序员用 JDBC 不得不写很多 try catch finally 之类的代码,这一点已经是众所周知的问题。众多的 O/R mapping 或者 JDBC 封装工具类,在吹自己的好处的时候,都不忘了和 JDBC 比较一把,“用我就不用写这么多乱七八糟的 try catch”。问题在于,既然 JDBC 设计的有这么多人觉得不好,为什么没有人去建议 Sun 公司改进一吧?这是一个非常让人迷惑的事情。
这里面暴露了 Java 中两个问题: Exception 语法问题、interface 语法问题。
Exception 应不应该用,在 C++ 时代就有很多争论,在目前的大多数比较有名气的开源项目中,要么,只用 C 不用 C++,要么用 C++ 但不用 Exception,用 C++ Exception 的很少。这里面的原因在于,在 C++ 中 throw Exception,会破坏结构化程序设计的一个最基本原则:一个函数只有一个入口,一个出口。在其他语言中,一个函数有多个出口也许没有什么问题,最多只是代码的可读性、维护性不好,在 C++ 中,一个致命的问题,资源释放问题,强烈要求,函数只能有一个出口。
比如如下代码:
funA(){
A *a = new A();
funT(a);
delete a;
}
这样的代码,如果一开始,funT 中没有 throw Exception,这样的代码没有自然释放问题;如果某一天,有人将 funT 中增加这么一段代码:
funT(A *a){
....
if(xx){
throw exception;
}
....
}
则以上函数 funA 中,就存在内存泄漏问题:如果funT 运行到 throw exception,funA 中 delete 根本就不会执行到。如果 funA 归程序员 jack 负责, funT 归 tom 负责,jack 只看 funA 也许永远也不会意识到 funA 有内存泄漏问题。
在 Java 中,虽然不存在内存泄漏问题,但是存在资源释放关闭问题,比如关闭文件之类的。像 Spring、Hibernate 之类的工具包,将 SQLException 封装成 RuntimeException ,同样让人迷惑。
比如以下 Java 伪代码:
open file;
read file;
dao.saveFileData(); // throw exception inside
close file;
如果 saveFileData 抛异常的话, close file 根本执行不到。按照目前流行的方法, DAO 函数抛异常都是 RuntimeException,编译器不会提醒你去 try catch,这里面出错的可能性大大提高。
目前已经有人在呼吁,Java coding 中也不要用 exception。
另一个问题是 Java 中 interface 语法问题。
Java 中 interface 语法非常糟糕,JDK 任何一个 interface 一旦发布后,做任何修改(增加函数、修改函数、去掉函数),都会导致已有的程序员代码,使用新的 JDK 编译不能通过问题。
比如,JDK 中有一个 interface 叫 Serializable, 这是一个空的 interface(非常莫名其妙的设计),假定某天 Sun 决定给这个 interface 需要增加 readObject,writeObject , 这就有问题了。很多已经写了这样的代码:
public class M implements Serializable{
....
}
如果新的 JDK 中,Serializable 多了两个函数,用新的 JDK 去编译已有的代码 class M,就会编译不通过。这实际上将 Sun 放在一个非常尴尬的处境:你可以在新的 JDK 中往 class 中增加函数,比如 Sun 可以在 JDK 1.3 省级到 1.4 的时候,往 String 类中增加一个函数 replaceAll,但是 Sun 不能改动任何 interface。不能升级 JDK 中的 interface 意味着,Sun 在 JDK 1.0 中发布的 interface ,在 JDK 1.4 中要原封不动,在以后的版本中也要永远不动。这个要求太高了!!!
为什么 Sun 写不出一个象 ADO 一样的 JDBC,不用抛 Exception 的 JDBC 规范出来?