java错误代码1603 错误

fluagen 的BLOG
用户名:fluagen
文章数:193
评论数:63
访问量:906778
注册日期:
阅读量:15368
阅读量:323
51CTO推荐博文
下面的文章是我译自Rod Johnson的"J2EE Design and Developement", 解答了我长久以来的一个疑问, 希望对大家有用。异常处理 - Checked还是Unchecked Java明确区分两种类型的异常. 那些扩展了java.lang.Exception的异常称为checked exceptions, 编译器要求这些异常必须被捕获或者重新抛出. 那些扩展了java.lang.RuntimeException的异常称为unchecked exceptions, 它们不是必须捕获的. 当然, 也可以捕获这些异常并相应地扩展调用栈, 就像通常对checked exceptions做的那样. Java是唯一的支持checked exceptions的主流语言, 而所有的C++和C#异常都相当于Java的unchecked exceptions.首先, 让我们考虑一下Java中接收异常时的行为. 在Sun提供的Java教程中提到了这一点, 参见其中的建议是在代码中使用checked exceptions: "因为Java语言不要求一个方法捕获运行时异常或定义抛出何种运行时异常, 对程序员来说,
仅抛出运行时异常或使所有的自定义异常都从RuntimeException继承就显得很有诱惑力. 这两种编程的便捷方法都使得程序员可以这样写Java代码, 免于Java编译器的唠唠叨叨的错误提示, 也不用定义或捕获任何异常. 这看上去很方便, 但是这种故意回避Java语言关于捕获异常和定义异常规范的要求的做法, 可能会对使用你的Java类的其他程序员造成问题.Checked exceptions表示了关于一个操作的一些有用的信息, 这项操作调用者无法控制, 但是调用者又需要知道这些信息. 比如, 文件系统可能已满, 或者远端关闭了连接, 又或者访问授权不足以执行这项操作.那么, 如果仅仅因为你不想定义异常规范就抛出一个RuntimeException或其子类, 你能得到什么呢? 很简单, 你能够抛出一个没有明确定义的异常. 或者说, 这是一种避免文档化一个方法能抛出的每一项异常的方法. 这好吗? 也许只比根本不文档化方法的语义好一点吧. 所以答案就是几乎从来都不应使用unchecked exceptions."总结一下, 正统的Java做法是: 使用checked exceptions, 而运行时异常(RuntimeException)预示编程上的错误.我曾经也同意这种观点. 但是, 在书写了成千上万个异常捕获代码块之后, 我得出这样的结论, 这种理论在实践中并不总是可行的. 我并不是唯一这么想的人.
既然在这一点上慢慢形成我自己的观点, 我注意到Bruce Eckel, 他是经典的Thinking in Java的作者, 也改变了他的观点. 现在Eckel提倡使用运行时异常, 并且怀疑checked exceptions是否只是一种不成功的试验, 应该从Java中抛弃. 参见Eckel声称观察表明, 当一个程序员关注一小段代码时, checked exceptions看上去是一种漂亮的想法, 可以避免很多错误. 但是, 在大规模的代码中情况正好相反. 可以参考Griffiths的"Exceptional Java", 这是另外一个关于checked exceptions引起的问题的研究.使用checked exceptions引起以下一些问题:1. 代码膨胀. 程序员必须书写代码捕获并忽略那些他们并不能合理地加以处理的异常, 他们将变得很泄气. 这是一种糟糕的编程实践, 经验表明它们发生得比我们想象的更为频繁. 即使是一个好的程序员也会偶尔忘记正确地将异常嵌套, 这意味着完整的调用栈将丢失, 异常中包含的信息就不再那么有用.2. 代码的可读性降低. 在例程中捕获那些不能合理加以处理的异常并马上重新抛出它们, 使得很难找到那些真正做一些事情的代码. Java的正统观点认为这一点只困扰那些懒惰的程序员, 我们应该简单地忽略这个问题. 然而, 这种观点忽略了事实. 例如, 设计Java核心库的人显然清楚地考虑过这个问题. 想象一下, 如果象java.util.Iterator这样的界面抛出checked exceptions而不是unchecked exceptions, 那么使用它们将是一场噩梦. JDO API是另外一个来自Sun自己的API的例子, 它使用unchecked exceptions. 相反, JDBC使用checked exceptions, 使用起来就很笨重.3. 没完没了地包装异常. 一个checked exceptions必须被捕获, 或者声明在可能遇到它们的那些方法的异常规范中. 这就造成一种选择, 可以重新抛出异常, 也可以将一个低级别的异常包装在一个新的高级别异常中, 然后重新抛出. 如果我们加入了一些有用的信息, 包装并重新抛出异常是很值得的. 但是, 如果原来的异常是不可恢复的, 包装它们就毫无价值. 如果使用unchecked exceptions, 在这种情况下将引起一个自动的栈回绕, 而使用checked exceptions, 我们无非做了一个等价的手工栈回绕, 并且在调用栈路径上的每一个方法中都要添加一些额外的毫无意义的代码, 只是为了包装异常. 主要是这个原因才促使我重新思考自己关于异常处理的态度.4. 脆弱的原型声明. 如果很多代码都使用了某个界面, 那么要声明一条额外的异常规范就会导致修改大量代码.5. 定义接口时, Checked exceptions并不总是工作得那么良好. 考虑Java教程中文件系统满的例子. 如果我们谈论的是一个使用文件系统的类, 这个例子没有问题. 如果我们处理的是一个仅仅承诺在某处(也许是数据库)存储数据的类, 情况又怎样呢? 我们肯定不想在这个类的接口中硬编码进对Java I/O API的依赖, 因为这个接口很可能有许多不同的实现. 若使用checked exceptions, 我们必须为这个接口创建一个新的存储介质无关的异常类型, 并且将文件系统异常包装其中. 这样做是否值得依赖于发生的异常是不是可恢复的. 如果不可恢复, 我们又一次做了无用功.很多这些问题归结于这样一个问题: 我们捕获了一个无法处理的异常, 被迫重新抛出一个包装过的异常. 这很讨厌, 很容易引起错误(因为很容易丢失调用栈), 并且没有用. 此时使用unchecked exceptions更佳. Unchecked exceptions会引发自动的栈回绕, 而且也是在发生致命错误时的正确行为. 我相信checked exceptions在一种情况下是有用的, 这一点不象Eckel, 也使我的观点不是那么的不正统. 当异常等同于方法的另外一个返回值时, 应使用checked exceptions, 更棒的是语言将帮助强制必须检查这一返回值. 我只是认为通常的Java约定过分强调了这一点. "Checked exceptions比许多老的语言中使用的错误返回值要好得多. 程序员迟早将不再检查错误返回值, 能使用编译器强制正确的错误处理真是太好了. 这样的checked exceptions应该象参数和返回值那样是API的一部分."然而, 我不建议使用checked exceptions, 除非调用者能处理它们. Checked exceptions尤其不应用来标示发生了一些致命错误, 这些错误不应由调用者来处理."如果调用者代码能做一些有意义的事情, 使用checked exceptions. 如果异常是致命的, 或者调用者不能通过捕获异常而有所收获, 使用unchecked exceptions. 记住你可以依赖于一个J2EE容器来捕获unchecked exceptions并记录它们."以下是选择checked exceptions还是unchecked exceptions的指南:问题 例子 肯定回答时的建议--------------------------------------------------所有调用者都应处理 定义和使用checked 这个问题吗? 异常是 exceptions, 以利用否只是函数的另外一 Java提供的编译时支持个返回值?--------------------------------------------------是否只有少数调用者 JDO异常 扩展RuntimeException.需要处理这个问题? 这使得调用者可以捕获异常, 但不强制所有调用者都这么做--------------------------------------------------是否发生了致命错误? 扩展RuntimeException.错误是不可恢复的吗?--------------------------------------------------还不清楚? 扩展RuntimeException.将可能抛出的异常都写进文档, 以便调用者决定是否捕获和捕获哪些异常--------------------------------------------------在包一级做一个决定, 决定每个包如何使用checked和unchecked exceptions. 将使用unchecked exceptions的决定写进文档, 因为很多程序员还不习惯它.
使用unchecked exceptions的唯一危险是没有正确地写文档. 使用unchecked exceptions时, 一定要将所有可能的异常写进文档, 让调用者选择是否捕获异常. 理想的情况下, 编译器应该强制将所有的异常写进Javadoc. 当分配JDBC连接这样的在所有情况下都应释放的资源时, 不管你是否需要捕获异常, 切记使用一个finalize块以保证正确的清除. 记住即使没有catch块, 仍然可以使用finalize块.未捕获的运行时异常将杀死执行的线程, 有时这成为避免使用运行时异常的一个理由. 在一些情况下这是一个合理的论据, 但是J2EE应用中这通常不是一个问题, 因为我们极少控制线程, 而是让应用服务器来做这个. 应用服务器将捕获和处理那些在应用代码中没有捕获的运行时异常, 而不会让这些异常挂起整个Java虚拟机. 在EJB容器中发生的一个未捕获的运行时异常将导致EJB容器抛弃当前的EJB实例. 如果发生的错误是致命的, 这通常没什么不对.说到底, 使用checked exception还是unchecked exception是一个观点的问题. 不光将采用的方式写进文档很重要, 尊重其他人的方法也很重要. 虽然我倾向于使用unchecked exception, 当维护或修改其他喜欢只使用checked exception的程序员的代码时, 我将采用他们的方法.
异常处理的良好实践方法无论使用checked exceptions还是unchecked exceptions, 我们总需要理异常嵌套的问题. 通常这发生在我们被迫捕获一个我们不能处理的异常, 而是重新抛出它们时. 这意味着我们必须将原始的嵌套的异常包装在一个新的异常中.有一些标准的异常, 比如javax.servlet.ServletException, 提供了这样的包装功能. 在我们自己的应用的异常之中, 我们需要定义或使用自定义的异常父类, 这些父类有一个以其原始异常为参数的构造函数, 并且重载了printStackTrace()方法来显示完整的调用栈, 包括原始异常的调用栈在内. 通常我们需要两个这样的父类, checked exceptions和unchecked exceptions各一个. (在JDK 1.4中不需要这么做, 因为它支持所有异常的嵌套.)在本书的示例代码中, 这两个类分别是com.interface21.core.NestedCheckedException和com.interface21.core.NestedRuntimeException. 除了分别继承自java.lang.Exception和java.lang.RuntimeException, 它们没什么不同. 这两个类都是抽象类, 它们的子类才有意义. NestedRuntimeException的定义如下:package com.interface21.import java.io.PrintSimport java.io.PrintW
public abstract class NestedRuntimeException extends RuntimeException {private Throwable rootCpublic NestedRuntimeException(String s) {super(s);}public NestedRuntimeException(String s, Throwable ex) {super(s);rootCause =}public Throwable getRootCause() {return rootC}public String getMessage() {if (rootCause == null) {return super.getMessage();} else {return super.getMessage() + "; nested exception is: nt" +rootCause.toString();}}public void printStackTrace(PrintStream ps) {if (rootCause == null) {super.printStackTrace(ps);} else {ps.println(this);rootCause.printStackTrace(ps);}}public void printStackTrace(PrintWriter pw) {if (rootCause == null) {super.printStackTrace(pw);} else {pw.println(this); rootCause.printStackTrace(pw);}}public void printStackTrace() {printStackTrace(System.err);}}Java 1.4在异常处理领域引进了受欢迎的改进. 不再需要写链式异常, 同时那些已经存在的象上面那样的代码工作起来也没有问题. java.lang.Throwable和java.lang.Exception都有了新的构造函数, 支持异常的嵌套, 并且java.lang.Throwable新增了一个方法void initCause(Throwable t)使得即使异常构造之后仍可以定义一个根异常. 这个方法应该只在构造函数没有定义嵌套异常的情况下被调用一次.Java 1.4相关的异常应该实现一个以嵌套异常为参数的构造函数, 它再调用新的异常构造函数. 这意味着我们总是可以象下面那样在一行代码中创建和抛出异常:catch (RootCauseException ex) {throw new MyJava14Exception("Detailed message", ex);}如果异常没有提供这样的构造函数, 我们需要使用稍多一点的代码, 象这样:catch (RootCauseException ex) {MyJava13Exception mex = new MyJava13Exception("Detailed message");mex.initCause(ex); }当使用象上面讨论的NestedRuntimeException那样的可嵌套异常时, 记得遵循它们自己的约定, 而不是Java 1.4那样的预定, 这样才能正常工作.J2EE中的异常当涉及J2EE应用时, 有几个特殊的问题需要考虑.分布式应用将遇到许多checked exceptions. 这部分是因为在那些Java的早期历史中, Sun有意这么做, 使得必须明确地使用远程调用. 所有的RMI调用, 包括那些EJB远程接口调用, 都抛出java.rmi.RemoteException, 这使得不可能做到本地调用和远程调用的透明. 这种决定大概是正确的, 因为本地调用和远程调用的透明性是很危险的, 特别是对性能. 但是, 这导致着我们经常书写代码来处理checked exceptions, 而这些异常仅仅意味着发生了致命的不值得重试的异常.在servlets和JSP页面中, 从J2EE系统级异常如java.rmi.RemoteException保护接口代码是很重要的. 许多程序员没有认识到这一点, 这导致很不幸的后果, 比如造成对系统框架层不必要的依赖和失去重试一些操作的机会, 这些操作本应该在更低的层次上已经重试过了. 在那些认识到这些问题的程序员中间, 我看到两种策略:1. 允许界面部分忽略这样的异常. 比如, 在所有处理呼入的WEB页请求的类的父类这样较高的层次上捕获异常,
这就允许子类在某个具有保护属性的抽象成员函数中抛出一类异常.2. 当业务逻辑而非远程过程调用引起异常时, 不管是checked还是unchecked的, 使用客户端方法来取消和远端系统的通讯并抛出异常. 这就是说客户端方法不应该模拟远端组件的接口, 远端接口总是抛出java.rmi.RemoteException. 这种方法称为Business delegate J2EE pattern, 是核心J2EE模式的一种.
了这篇文章
类别:┆阅读(0)┆评论(0)页面导航:
→ 正文内容 JAVA中的异常与错误处理
深入探讨JAVA中的异常与错误处理
这篇文章详细介绍了JAVA中的异常与错误处理,有需要的朋友可以参考一下
异常与错误:  异常:  在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发人员)已经犯了个错误,现在有一个机会来修改它。Java中使用异常类来表示异常,不同的异常类代表了不同的异常。但是在Java中所有的异常都有一个基类,叫做Exception。  错误:  它指的是一个合理的应用程序不能截获的严重的问题。大多数都是反常的情况。错误是VM的一个故障(虽然它可以是任何系统级的服务)。所以,错误是很难处理的,一般的开发人员(当然不是你)是无法处理这些错误的,比如内存溢出。 和异常一样,在Java中用错误类来表示错误,不同的错误类代表了不同的错误。 但是在Java中所有的错误都有一个基类,叫做Error。  综上,我们可以知道异常和错误最本质的区别就是异常能被开发人员处理而错误时系统本来自带的,一般无法处理也不需要我们程序员来处理。  1.一个异常是在一个程序执行过程中出现的一个事件,它中断了正常指令的运行  2.错误,偏离了可接受的代码行为的一个动作或实例  异常的结构分类:  1、运行时异常(未检查异常)  2、编译时异常(已检查异常)  运行异常即是RuntimeE其余的全部为编译异常  在Java中异常Exception和错误Error有个共同的父类Throwable。  Error Exception  runtimeException几个子类  1、 java.lang.ArrayIndexOutOfBoundsException  数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。  2、java.lang.ArithmeticException  算术条件异常。譬如:整数除零等。  3、java.lang.NullPointerException  空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的  属性、计算null对象的长度、使用throw语句抛出null等等  4、java.lang.ClassNotFoundException  找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出  该异常。  对异常的处理:  try{}catch{}  try{}catch{}finally{}无论有无异常finally代码块都会被执行  try{}finally{}也是可以组合使用的但是catch{}finally{}不可以  注意:在继承关系中,子类覆盖父类的方法,抛出异常的范围不能比父类更宽泛  异常的使用  在异常的使用这一部分主要是演示代码,都是我们平常写代码的过程中会遇到的(当然只是一小部分),抛砖引玉吗!  例1. 这个例子主要通过两个方法对比来演示一下有了异常以后代码的执行流程。 代码如下:public static void testException1() {int[] ints = new int[] { 1, 2, 3, 4 };System.out.println("异常出现前");try {System.out.println(ints[4]);System.out.println("我还有幸执行到吗");// 发生异常以后,后面的代码不能被执行} catch (IndexOutOfBoundsException e) {System.out.println("数组越界错误");}System.out.println("异常出现后");}/*output:  异常出现前  数组越界错误  常出现后  */ 代码如下:public static void testException2() {int[] ints = new int[] { 1, 2, 3, 4 };System.out.println("异常出现前");System.out.println(ints[4]);System.out.println("我还有幸执行到吗");// 发生异常以后,他后面的代码不能被执行}  首先指出例子中的不足之处,IndexOutofBoundsException是一个非受检异常,所以不用try...catch...显示捕捉,但是我的目的是对同一个异常用不同的处理方式,看它会有什么不同的而结果(这里也就只能用它将就一下了)。异常出现时第一个方法只是跳出了try块,但是它后面的代码会照样执行的。但是第二种就不一样了直接跳出了方法,比较强硬。从第一个方法中我们看到,try...catch...是一种"事务性"的保障,它的目的是保证程序在异常的情况下运行完毕,同时它还会告知程序员程序中出错的详细信息(这种详细信息有时要依赖于程序员设计)。  例2. 重新抛出异常 代码如下:public class Rethrow {public static void readFile(String file) throws FileNotFoundException {try {BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));} catch (FileNotFoundException e) {e.printStackTrace();System.err.println("不知道如何处理该异常或者根本不想处理它,但是不做处理又不合适,这是重新抛出异常交给上一级处理");//重新抛出异常}}public static void printFile(String file) {try {readFile(file);} catch (FileNotFoundException e) {e.printStackTrace();}}public static void main(String[] args) {printFile("D:/file");}}  异常的本意是好的,让我们试图修复程序,但是现实中我们修复的几率很小,我们很多时候就是用它来记录出错的信息。如果你厌倦了不停的处理异常,重新抛出异常对你来说可能是一个很好的解脱。原封不动的把这个异常抛给上一级,抛给调用这个方法的人,让他来费脑筋吧。这样看来,java异常(当然指的是受检异常)又给我们平添很多麻烦,尽管它的出发点是好的。  例3. 异常链的使用及异常丢失 代码如下:ExceptionA,ExceptionB,ExceptionCpublic class ExceptionA extends Exception {public ExceptionA(String str) {super();}}public class ExceptionB extends ExceptionA {public ExceptionB(String str) {super(str);}}public class ExceptionC extends ExceptionA {public ExceptionC(String str) {super(str);}}  异常丢失的情况: 代码如下:public class NeverCaught {static void f() throws ExceptionB{throw new ExceptionB("exception b");}static void g() throws ExceptionC {try {f();} catch (ExceptionB e) {ExceptionC c = new ExceptionC("exception a");}}public static void main(String[] args) {try {g();} catch (ExceptionC e) {e.printStackTrace();}}}/*exception.ExceptionCat exception.NeverCaught.g(NeverCaught.java:12)at exception.NeverCaught.main(NeverCaught.java:19)*/为什么只是打印出来了ExceptionC而没有打印出ExceptionB呢?这个还是自己分析一下吧!  上面的情况相当于少了一种异常,这在我们排错的过程中非常的不利。那我们遇到上面的情况应该怎么办呢?这就是异常链的用武之地:保存异常信息,在抛出另外一个异常的同时不丢失原来的异常。 代码如下:public class NeverCaught {static void f() throws ExceptionB{throw new ExceptionB("exception b");}static void g() throws ExceptionC {try {f();} catch (ExceptionB e) {ExceptionC c = new ExceptionC("exception a");//异常连c.initCause(e);}}public static void main(String[] args) {try {g();} catch (ExceptionC e) {e.printStackTrace();}}}/*exception.ExceptionCat exception.NeverCaught.g(NeverCaught.java:12)at exception.NeverCaught.main(NeverCaught.java:21)Caused by: exception.ExceptionBat exception.NeverCaught.f(NeverCaught.java:5)at exception.NeverCaught.g(NeverCaught.java:10)... 1 more*/  这个异常链的特性是所有异常均具备的,因为这个initCause()方法是从Throwable继承的。  例4. 清理工作  清理工作对于我们来说是必不可少的,因为如果一些消耗资源的操作,比如IO,JDBC。如果我们用完以后没有及时正确的关闭,那后果会很严重,这意味着内存泄露。异常的出现要求我们必须设计一种机制不论什么情况下,资源都能及时正确的清理。这就是finally。 代码如下:public void readFile(String file) {BufferedReader reader =try {reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));// do some other work} catch (FileNotFoundException e) {e.printStackTrace();} finally {try {reader.close();} catch (IOException e) {e.printStackTrace();}}}例子非常的简单,是一个读取文件的例子。这样的例子在JDBC操作中也非常的常见。(所以,我觉得对于资源的及时正确清理是一个程序员的基本素质之一。)  Try...finally结构也是保证资源正确关闭的一个手段。如果你不清楚代码执行过程中会发生什么异常情况会导致资源不能得到清理,那么你就用try对这段"可疑"代码进行包装,然后在finally中进行资源的清理。举一个例子: 代码如下:public void readFile() {BufferedReader reader =try {reader = new BufferedReader(new InputStreamReader(new FileInputStream("file")));// do some other work//close readerreader.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}我们注意一下这个方法和上一个方法的区别,下一个人可能习惯更好一点,及早的关闭reader。但是往往事与愿违,因为在reader.close()以前异常随时可能发生,这样的代码结构不能预防任何异常的出现。因为程序会在异常出现的地方跳出,后面的代码不能执行(这在上面应经用实例证明过)。这时我们就可以用try...finally来改造: 代码如下:public void readFile() {BufferedReader reader =try {try {reader = new BufferedReader(new InputStreamReader(new FileInputStream("file")));// do some other work// close reader} finally {reader.close();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}及早的关闭资源是一种良好的行为,因为时间越长你忘记关闭的可能性越大。这样在配合上try...finally就保证万无一失了(不要嫌麻烦,java就是这么中规中矩)。  再说一种情况,假如我想在构造方法中打开一个文件或者创建一个JDBC连接,因为我们要在其他的方法中使用这个资源,所以不能在构造方法中及早的将这个资源关闭。那我们是不是就没辙了呢?答案是否定的。看一下下面的例子: 代码如下:public class ResourceInConstructor {BufferedReader reader =public ResourceInConstructor() {try {reader = new BufferedReader(new InputStreamReader(new FileInputStream("")));} catch (FileNotFoundException e) {e.printStackTrace();}}public void readFile() {try {while(reader.readLine()!=null) {//do some work}} catch (IOException e) {e.printStackTrace();}}public void dispose() {try {reader.close();} catch (IOException e) {e.printStackTrace();}}}  这一部分讲的多了一点,但是异常确实是看起来容易用起来难的东西呀,java中还是有好多的东西需要深挖的
您可能感兴趣的文章:
上一篇:下一篇:
最 近 更 新
热 点 排 行
12345678910Java异常那些不得不说的事 - 上善若水任方圆 - ITeye技术网站
博客分类:
一、在finally块中做数据回收操作
比如数据库连接都是很宝贵的,所以最好在finally中关闭连接。
JDBCAgent jdbc = new JDBCAgent();
jdbc.excute("select * from ctp_log");
}catch(SQLException e){
jdbc.close();
二、不要在异常finally块中定义返回值
如下代码,虽然有很多返回值,但如果真的执行,该代码的返回值永远是3,因为finally是最终执行代码,将其它返回值全部覆盖了!
if(x = 1){
return throw new RuntimeException();
}catch(Exception e){
三、覆写Exception的fillInStackTrace方法能提高异常性能
异常性能差是因为fillInStackTrace方法,该方法是带锁的并且需要填充线程异常栈信息。
而我们的业务类异常是不需要记录异常栈的,可以考虑覆写fillInStackTrace方法减小性能开支(据说覆写该方法能提高10倍性能)。
(注:什么是业务类,参照第四点)
public class AccountException extends Exception {
public Throwable fillInStackTrace() {
四、业务上的错误使用异常更加OOP
以登录为例,简单的登录方法通过返回boolean即可确认是否登录成功,但如果功能日趋复杂怎么办?通过抛出业务类异常的方式来解析错误信息可读性非常好。
userManager.login(account,passowrd,identify);
}catch(AccountException e){
//账号出错
}catch(PasswordException e){
//密码出错
}catch(IdentifyException e){
//验证码错误
}catch(AccountDisableException e){
//账号被禁用
五、使用正确的log记录异常信息
Log logger = LogFactory.getLog(Demo.class);
}catch(SQLException e){
throw new BusinessException(e);
//√发生该异常会影响后续数据完整性的时候,应该抛出中止操作
logger.error(e.getLocalizedMessage(),e);
//√记录完整的log日志方便调试
log.error(e);
//×这种记录方式只能记录很少的异常信息(连异常发生的位置都没有,记了白记)
e.printStackTrace();
//×仅仅将异常打到控制台,开发调试还可以,一旦到生产环境就很难跟踪异常
System.out.print(e);
六、除了记录异常,记得记录详细参数信息
很多时候通过logger.error(e.getLocalizedMessage(),e)这种记录日志的方式都不一定分析出异常原因。
比如出现一个SQL异常,log日志可能会这样提示:ORA-00936: 缺少表达式。试问这样的错误你能分析这句SQL到底哪儿出了问题吗?不能!所以记录日志的时候最好是把SQL及参数都打印出来,如下例所示。
但记录日志要有分寸,别把客户的机密信息记录出来,如果被发现,我们会负责的!
public List find(Long id,String name){
String sql = ......;
JdbcAgent.excute(sql);
}catch(Exception e){
logger.error("sql异常:"+sql+" 参数ID:"+id+",参数name:"+name,e);
(注:作为研发你可能会说:我通过Eclipse debugger调试就可以知道原因了。但从长远考虑:假如系统已经部署到客户环境上,他们允许你debugger调试吗?不能!所以最好的求助工具就是详细的log日志!)
七、从子到父顺序捕获异常
如下所示,假如抛出的是BusinessException异常,那么第二个catch就能捕获到。
如果catch(Exception e)在catch(BusinessException e)之前,则该异常会被catch(Exception e)捕获而不会进catch(BusinessException e)。
}catch(RuntimeException e){
}catch(BusinessException e){//BusinessException extends Exception
}catch(Exception e){
八、使用isInfoEnabled和isDebugEnabled
在看spring和apache等开源体系下的代码时,你会发现在记录log日志时总是看到如下风格的代码:
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startT
("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
为什么记录debug和info日志前要加个判断?其实原因很简单:提高效率!如上代码所示,在记录日志时进行了字符串拼接,要知道这是会消耗一定资源的。假如当前log日志级别是error,则debug和info是不会被输出的,如果加了if判断则log.debug/info中的字符串拼接就不会执行,自然提高了效率。
在小系统看不出差距,但如果是高并发的系统下,少执行一句代码能明显减小服务器的压力,精细化的代码是有必要的!
注意:下面这样的代码是提高不了性能的,因为在if之前就已经准备好log信息:
long elapsedTime = System.currentTimeMillis() - startT
String info = "Root WebApplicationContext: initialization completed in " + elapsedTime + " ms";
if (logger.isInfoEnabled()) {
浏览: 1001541 次
来自: 成都
很好用! 问题解决!O(∩_∩)O谢谢
根号九加一 写道root的值是什么,是什么路径,能提供一下吗? ...
root的值是什么,是什么路径,能提供一下吗?
[url] [/url]
[*]& target=&_blank&q ...

我要回帖

更多关于 java 的文章

 

随机推荐