`
klyuan
  • 浏览: 181930 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

J2EE项目异常处理

    博客分类:
  • java
阅读更多
J2EE项目异常处理
               
       为什么要在J2EE项目中谈异常处理呢?可能许多java初学者都想说:“异常处理不就是try….catch…finally吗?这谁都会啊!”。笔者在初学java时也是这样认为的。如何在一个多层的j2ee项目中定义相应的异常类?在项目中的每一层如何进行异常处理?异常何时被抛出?异常何时被记录?异常该怎么记录?何时需要把checked Exception转化成unchecked Exception ,何时需要把unChecked Exception转化成checked Exception?异常是否应该呈现到前端页面?如何设计一个异常框架?本文将就这些问题进行探讨。
1. JAVA异常处理
在面向过程式的编程语言中,我们可以通过返回值来确定方法是否正常执行。比如在一个c语言编写的程序中,如果方法正确的执行则返回1.错误则返回0。在vb或delphi开发的应用程序中,出现错误时,我们就弹出一个消息框给用户。
通过方法的返回值我们并不能获得错误的详细信息。可能因为方法由不同的程序员编写,当同一类错误在不同的方法出现时,返回的结果和错误信息并不一致。
所以java语言采取了一个统一的异常处理机制。
什么是异常?运行时发生的可被捕获和处理的错误。
在java语言中,Exception是所有异常的父类。任何异常都扩展于Exception类。Exception就相当于一个错误类型。如果要定义一个新的错误类型就扩展一个新的Exception子类。采用异常的好处还在于可以精确的定位到导致程序出错的源代码位置,并获得详细的错误信息。
Java异常处理通过五个关键字来实现,try,catch,throw ,throws, finally。具体的异常处理结构由try….catch….finally块来实现。try块存放可能出现异常的java语句,catch用来捕获发生的异常,并对异常进行处理。Finally块用来清除程序中未释放的资源。不管理try块的代码如何返回,finally块都总是被执行。
一个典型的异常处理代码
java 代码
  1.   
  2. public String getPassword(String userId)throws DataAccessException{   
  3. String sql = “select password from userinfo where userid=’”+userId +”’”;   
  4. String password = null;   
  5. Connection con = null;   
  6. Statement s = null;   
  7. ResultSet rs = null;   
  8. try{   
  9.  con = getConnection();//获得数据连接   
  10.  s = con.createStatement();   
  11.  rs = s.executeQuery(sql);   
  12.  while(rs.next()){   
  13.     password = rs.getString(1);   
  14.  }   
  15.  rs.close();   
  16.  s.close();   
  17.      
  18. }   
  19. Catch(SqlException ex){   
  20.  throw new DataAccessException(ex);   
  21. }   
  22. finally{   
  23.  try{   
  24.       if(con != null){   
  25.         con.close();   
  26.       }   
  27.  }   
  28.    Catch(SQLException sqlEx){   
  29.      throw new DataAccessException(“关闭连接失败!”,sqlEx);   
  30.    }   
  31. }   
  32. return password;   
  33. }   
  34.    
可以看出Java的异常处理机制具有的优势:
给错误进行了统一的分类,通过扩展Exception类或其子类来实现。从而避免了相同的错误可能在不同的方法中具有不同的错误信息。在不同的方法中出现相同的错误时,只需要throw 相同的异常对象即可。
获得更为详细的错误信息。通过异常类,可以给异常更为详细,对用户更为有用的错误信息。以便于用户进行跟踪和调试程序。
把正确的返回结果与错误信息分离。降低了程序的复杂度。调用者无需要对返回结果进行更多的了解。
强制调用者进行异常处理,提高程序的质量。当一个方法声明需要抛出一个异常时,那么调用者必须使用try….catch块对异常进行处理。当然调用者也可以让异常继续往上一层抛出。
 
2. Checked 异常 还是 unChecked 异常?
Java异常分为两大类:checked 异常和unChecked 异常。所有继承java.lang.Exception 的异常都属于checked异常。所有继承java.lang.RuntimeException的异常都属于unChecked异常。
当一个方法去调用一个可能抛出checked异常的方法,必须通过try…catch块对异常进行捕获进行处理或者重新抛出。
我们看看Connection接口的createStatement()方法的声明。
public Statement createStatement() throws SQLException;
      
   SQLException是checked异常。当调用createStatement方法时,java强制调用者必须对SQLException进行捕获处理。
java 代码
  1.        public String getPassword(String userId){   
  2.        try{   
  3.        ……   
  4.               Statement s = con.createStatement();   
  5.               ……   
  6.        Catch(SQLException sqlEx){   
  7.               ……   
  8.    }   
  9. ……   
  10. }   
或者
java 代码
  1. public String getPassword(String userId)throws SQLException{   
  2.    Statement s = con.createStatement();   
  3. }  
(当然,像Connection,Satement这些资源是需要及时关闭的,这里仅是为了说明checked 异常必须强制调用者进行捕获或继续抛出)
 
unChecked异常也称为运行时异常,通常RuntimeException都表示用户无法恢复的异常,如无法获得数据库连接,不能打开文件等。虽然用户也可以像处理checked异常一样捕获unChecked异常。但是如果调用者并没有去捕获unChecked异常时,编译器并不会强制你那么做。
 
比如一个把字符转换为整型数值的代码如下:
 
java 代码
  1. String str = “123”;   
  2. int value = Integer.parseInt(str);  
 
parseInt的方法签名为:
java 代码
  1. public static int parseInt(String s) throws NumberFormatException  
 
当传入的参数不能转换成相应的整数时,将会抛出NumberFormatException。因为NumberFormatException扩展于RuntimeException,是unChecked异常。所以调用parseInt方法时无需要try…catch
 
因为java不强制调用者对unChecked异常进行捕获或往上抛出。所以程序员总是喜欢抛出unChecked异常。或者当需要一个新的异常类时,总是习惯的从RuntimeException扩展。当你去调用它些方法时,如果没有相应的catch块,编译器也总是让你通过,同时你也根本无需要去了解这个方法倒底会抛出什么异常。看起来这似乎倒是一个很好的办法,但是这样做却是远离了java异常处理的真实意图。并且对调用你这个类的程序员带来误导,因为调用者根本不知道需要在什么情况下处理异常。而checked异常可以明确的告诉调用者,调用这个类需要处理什么异常。如果调用者不去处理,编译器都会提示并且是无法编译通过的。当然怎么处理是由调用者自己去决定的。
 
       所以Java推荐人们在应用代码中应该使用checked异常。就像我们在上节提到运用异常的好外在于可以强制调用者必须对将会产生的异常进行处理。包括在《java Tutorial》等java官方文档中都把checked异常作为标准用法。
       使用checked异常,应意味着有许多的try…catch在你的代码中。当在编写和处理越来越多的try…catch块之后,许多人终于开始怀疑checked异常倒底是否应该作为标准用法了。
甚至连大名鼎鼎的《thinking in java》的作者Bruce Eckel也改变了他曾经的想法。Bruce Eckel甚至主张把unChecked异常作为标准用法。并发表文章,以试验checked异常是否应该从java中去掉。Bruce Eckel语:“当少量代码时,checked异常无疑是十分优雅的构思,并有助于避免了许多潜在的错误。但是经验表明,对大量代码来说结果正好相反”
关于checked异常和unChecked异常的详细讨论可以参考
 
使用checked异常会带来许多的问题。
       checked异常导致了太多的try…catch 代码
              可能有很多checked异常对开发人员来说是无法合理地进行处理的,比如SQLException。而开发人员却不得不去进行try…catch。当开发人员对一个checked异常无法正确的处理时,通常是简单的把异常打印出来或者是干脆什么也不干。特别是对于新手来说,过多的checked异常让他感到无所适从。
java 代码
  1.        try{   
  2.        ……   
  3.               Statement s = con.createStatement();   
  4.               ……   
  5.        Catch(SQLException sqlEx){   
  6.               sqlEx.PrintStackTrace();   
  7.    }   
  8.    或者   
  9.        try{   
  10.        ……   
  11.               Statement s = con.createStatement();   
  12.               ……   
  13.        Catch(SQLException sqlEx){   
  14.           //什么也不干   
  15. }   
 
checked异常导致了许多难以理解的代码产生
        当开发人员必须去捕获一个自己无法正确处理的checked异常,通常的是重新封装成一个新的异常后再抛出。这样做并没有为程序带来任何好处。反而使代码晚难以理解。
就像我们使用JDBC代码那样,需要处理非常多的try…catch.,真正有用的代码被包含在try…catch之内。使得理解这个方法变理困难起来
checked异常导致异常被不断的封装成另一个类异常后再抛出
java 代码
  1.         public void methodA()throws ExceptionA{   
  2.          …..          
  3.           throw new ExceptionA();        
  4. }   
  5.           
  6. public void methodB()throws ExceptionB{   
  7.    try{   
  8.       methodA();   
  9.       ……   
  10.    }catch(ExceptionA ex){   
  11.    throw new ExceptionB(ex);   
  12.    }   
  13. }   
  14.            
  15.         Public void methodC()throws ExceptinC{   
  16.        try{   
  17.          methodB();   
  18.          …   
  19.        }   
  20.        catch(ExceptionB ex){   
  21.           throw new ExceptionC(ex);   
  22.         }   
  23.     }   
我们看到异常就这样一层层无休止的被封装和重新抛出。
 
checked异常导致破坏接口方法
   一个接口上的一个方法已被多个类使用,当为这个方法额外添加一个checked异常时,那么所有调用此方法的代码都需要修改。
 
可见上面这些问题都是因为调用者无法正确的处理checked异常时而被迫去捕获和处理,被迫封装后再重新抛出。这样十分不方便,并不能带来任何好处。在这种情况下通常使用unChecked异常。
chekced异常并不是无一是处,checked异常比传统编程的错误返回值要好用得多。通过编译器来确保正确的处理异常比通过返回值判断要好得多。
如果一个异常是致命的,不可恢复的。或者调用者去捕获它没有任何益处,使用unChecked异常。
如果一个异常是可以恢复的,可以被调用者正确处理的,使用checked异常
在使用unChecked异常时,必须在在方法声明中详细的说明该方法可能会抛出的unChekced异常。由调用者自己去决定是否捕获unChecked异常
 
倒底什么时候使用checked异常,什么时候使用unChecked异常?并没有一个绝对的标准。但是笔者可以给出一些建议
当所有调用者必须处理这个异常,可以让调用者进行重试操作;或者该异常相当于该方法的第二个返回值。使用checked异常。
这个异常仅是少数比较高级的调用者才能处理,一般的调用者不能正确的处理。使用unchecked异常。有能力处理的调用者可以进行高级处理,一般调用者干脆就不处理。
这个异常是一个非常严重的错误,如数据库连接错误,文件无法打开等。或者这些异常是与外部环境相关的。不是重试可以解决的。使用unchecked异常。因为这种异常一旦出现,调用者根本无法处理。
如果不能确定时,使用unchecked异常。并详细描述可能会抛出的异常,以让调用者决定是否进行处理。
 
3.  设计一个新的异常类
在设计一个新的异常类时,首先看看是否真正的需要这个异常类。一般情况下尽量不要去设计新的异常类,而是尽量使用java中已经存在的异常类。
java 代码
  1. IllegalArgumentException, UnsupportedOperationException  
 
不管是新的异常是chekced异常还是unChecked异常。我们都必须考虑异常的嵌套问题。
java 代码
  1. public void methodA()throws ExceptionA{   
  2.          …..          
  3.           throw new ExceptionA();        
  4. }   
 
方法methodA声明会抛出ExceptionA.
 
public void methodB()throws ExceptionB
methodB声明会抛出ExceptionB,当在methodB方法中调用methodA时,ExceptionA是无法处理的,所以ExceptionA应该继续往上抛出。一个办法是把methodB声明会抛出ExceptionA.但这样已经改变了MethodB的方法签名。一旦改变,则所有调用methodB的方法都要进行改变。
另一个办法是把ExceptionA封装成ExceptionB,然后再抛出。如果我们不把ExceptionA封装在ExceptionB中,就丢失了根异常信息,使得无法跟踪异常的原始出处。
java 代码
  1. public void methodB()throws ExceptionB{   
  2.    try{   
  3.       methodA();   
  4.       ……   
  5.    }catch(ExceptionA ex){   
  6.      throw new ExceptionB(ex);   
  7.    }   
  8. }  
 
   如上面的代码中,ExceptionB嵌套一个ExceptionA.我们暂且把ExceptionA称为“起因异常”,因为ExceptionA导致了ExceptionB的产生。这样才不使异常信息丢失。
所以我们在定义一个新的异常类时,必须提供这样一个可以包含嵌套异常的构造函数。并有一个私有成员来保存这个“起因异常”。
java 代码
  1. public Class ExceptionB extends Exception{   
  2. private Throwable cause;   
  3.     
  4. public ExceptionB(String msg, Throwable ex){   
  5.  super(msg);   
  6.  this.cause = ex;   
  7. }   
  8.     
  9. public ExceptionB(String msg){   
  10.  super(msg);   
  11. }   
  12.     
  13. public ExceptionB(Throwable ex){   
  14.  this.cause = ex;   
  15. }   
  16. }   
当然,我们在调用printStackTrace方法时,需要把所有的“起因异常”的信息也同时打印出来。所以我们需要覆写printStackTrace方法来显示全部的异常栈跟踪。包括嵌套异常的栈跟踪。
java 代码
  1. public void printStackTrace(PrintStrean ps){   
  2. if(cause == null){   
  3.  super.printStackTrace(ps);   
  4. }else{   
  5.  ps.println(this);   
  6.  cause.printStackTrace(ps);   
  7. }   
  8. }   
 
一个完整的支持嵌套的checked异常类源码如下。我们在这里暂且把它叫做NestedException
 
java 代码
  1. public NestedException extends Exception{   
  2. private Throwable cause;   
  3. public NestedException (String msg){   
  4.  super(msg);   
  5. }   
  6.     
  7. public NestedException(String msg, Throwable ex){   
  8.  super(msg);   
  9.  This.cause = ex;   
  10. }   
  11.     
  12. public Throwable getCause(){   
  13.  return (this.cause == null ? this :this.cause);   
  14. }   
  15.     
  16. public getMessage(){   
  17.  String message = super.getMessage();   
  18.  Throwable cause = getCause();   
  19.    if(cause != null){   
  20.      message = message + “;nested Exception is ” + cause;   
  21.    }   
  22.  return message;   
  23. }   
  24. public void printStackTrace(PrintStream ps){   
  25.  if(getCause == null){   
  26.     super.printStackTrace(ps);   
  27.        
  28.  }else{   
  29.  ps.println(this);   
  30.  getCause().printStackTrace(ps);   
  31.  }   
  32. }   
  33.     
  34. public void printStackTrace(PrintWrite pw){   
  35.  if(getCause() == null){   
  36.     super.printStackTrace(pw);   
  37.  }   
  38.  else{   
  39.     pw.println(this);   
  40.     getCause().printStackTrace(pw);   
  41.  }   
  42. }   
  43. public void printStackTrace(){   
  44.  printStackTrace(System.error);   
  45. }   
  46. }   
  47.     
同样要设计一个unChecked异常类也与上面一样。只是需要继承RuntimeException。
 
 
4.  如何记录异常
作为一个大型的应用系统都需要用日志文件来记录系统的运行,以便于跟踪和记录系统的运行情况。系统发生的异常理所当然的需要记录在日志系统中。
java 代码
  1. public String getPassword(String userId)throws NoSuchUserException{   
  2. UserInfo user = userDao.queryUserById(userId);   
  3. If(user == null){   
  4.  Logger.info(“找不到该用户信息,userId=”+userId);   
  5.  throw new NoSuchUserException(“找不到该用户信息,userId=”+userId);   
  6. }   
  7. else{   
  8.  return user.getPassword();   
  9. }   
  10. }   
  11.     
  12. public void sendUserPassword(String userId)throws Exception {   
  13. UserInfo user = null;   
  14. try{   
  15.   user = getPassword(userId);   
  16.    //……..   
  17.  sendMail();   
  18.  //   
  19. }catch(NoSuchUserException ex)(   
  20.    logger.error(“找不到该用户信息:”+userId+ex);   
  21.    throw new Exception(ex);   
  22. }   
 
我们注意到,一个错误被记录了两次.在错误的起源位置我们仅是以info级别进行记录。而在sendUserPassword方法中,我们还把整个异常信息都记录了。
笔者曾看到很多项目是这样记录异常的,不管三七二一,只有遇到异常就把整个异常全部记录下。如果一个异常被不断的封装抛出多次,那么就被记录了多次。那么异常倒底该在什么地方被记录?
异常应该在最初产生的位置记录
 
如果必须捕获一个无法正确处理的异常,仅仅是把它封装成另外一种异常往上抛出。不必再次把已经被记录过的异常再次记录。
 
如果捕获到一个异常,但是这个异常是可以处理的。则无需要记录异常
 
java 代码
  1. public Date getDate(String str){   
  2.  Date applyDate = null;   
  3. SimpleDateFormat format = new SimpleDateFormat(“MM/dd/yyyy”);   
  4. try{   
  5.  applyDate = format.parse(applyDateStr);   
  6. }   
  7. catch(ParseException ex){   
  8.  //乎略,当格式错误时,返回null   
  9. }   
  10. return applyDate;   
  11. }   
 
捕获到一个未记录过的异常或外部系统异常时,应该记录异常的详细信息
java 代码
  1. try{   
  2.        ……   
  3.         String sql=”select * from userinfo”;   
  4.               Statement s = con.createStatement();   
  5.               ……   
  6.        Catch(SQLException sqlEx){   
  7.           Logger.error(“sql执行错误”+sql+sqlEx);   
  8. }   
      
   究竟在哪里记录异常信息,及怎么记录异常信息,可能是见仁见智的问题了。甚至有些系统让异常类一记录异常。当产生一个新异常对象时,异常信息就被自动记录。
java 代码
  1.   public class BusinessException extends Exception {   
  2.       private void logTrace() {   
  3.           StringBuffer buffer=new StringBuffer();   
  4.           buffer.append("Business Error in Class: ");   
  5.           buffer.append(getClassName());   
  6.           buffer.append(",method: ");   
  7.           buffer.append(getMethodName());   
  8.           buffer.append(",messsage: ");   
  9.           buffer.append(this.getMessage());   
  10.           logger.error(buffer.toString());   
  11.              
  12. }   
  13. public BusinessException(String s) {   
  14.          super(s);   
  15. race();   
  16. }   
这似乎看起来是十分美妙的,其实必然导致了异常被重复记录。同时违反了“类的职责分配原则”,是一种不好的设计。记录异常不属于异常类的行为,记录异常应该由专门的日志系统去做。并且异常的记录信息是不断变化的。我们在记录异常同应该给更丰富些的信息。以利于我们能够根据异常信息找到问题的根源,以解决问题。
虽然我们对记录异常讨论了很多,过多的强调这些反而使开发人员更为疑惑,一种好的方式是为系统提供一个异常处理框架。由框架来决定是否记录异常和怎么记录异常。而不是由普通程序员去决定。但是了解些还是有益的。
5. J2EE项目中的异常处理
目前,J2ee项目一般都会从逻辑上分为多层。比较经典的分为三层:表示层,业务层,集成层(包括数据库访问和外部系统的访问)。
J2ee项目有着其复杂性,J2ee项目的异常处理需要特别注意几个问题。
在分布式应用时,我们会遇到许多checked异常。所有RMI调用(包括EJB远程接口调用)都会抛出java.rmi.RemoteException;同时RemoteException是checked异常,当我们在业务系统中进行远程调用时,我们都需要编写大量的代码来处理这些checked异常。而一旦发生RemoteException这些checked异常对系统是非常严重的,几乎没有任何进行重试的可能。也就是说,当出现RemoteException这些可怕的checked异常,我们没有任何重试的必要性,却必须要编写大量的try…catch代码去处理它。一般我们都是在最底层进行RMI调用,只要有一个RMI调用,所有上层的接口都会要求抛出RemoteException异常。因为我们处理RemoteException的方式就是把它继续往上抛。这样一来就破坏了我们业务接口。RemoteException这些J2EE系统级的异常严重的影响了我们的业务接口。我们对系统进行分层的目的就是减少系统之间的依赖,每一层的技术改变不至于影响到其它层。
 
java 代码
  1. //   
  2. public class UserSoaImpl implements UserSoa{   
  3.    public UserInfo getUserInfo(String userId)throws RemoteException{   
  4.       //……   
  5. 远程方法调用.   
  6.       //……   
  7.    }   
  8. }   
  9. public interface UserManager{   
  10.    public UserInfo getUserInfo(Stirng userId)throws RemoteException;   
  11. }   
 
同样JDBC访问都会抛出SQLException的checked异常。
 
为了避免系统级的checked异常对业务系统的深度侵入,我们可以为业务方法定义一个业务系统自己的异常。针对像SQLException,RemoteException这些非常严重的异常,我们可以新定义一个unChecked的异常,然后把SQLException,RemoteException封装成unChecked异常后抛出。
如果这个系统级的异常是要交由上一级调用者处理的,可以新定义一个checked的业务异常,然后把系统级的异常封存装成业务级的异常后再抛出。
一般地,我们需要定义一个unChecked异常,让集成层接口的所有方法都声明抛出这unChecked异常
java 代码
  1. public DataAccessException extends RuntimeException{   
  2.  ……   
  3. }   
  4. public interface UserDao{   
  5.  public String getPassword(String userId)throws DataAccessException;   
  6. }   
  7.     
  8. public class UserDaoImpl implements UserDAO{   
  9. public String getPassword(String userId)throws DataAccessException{   
  10.  String sql = “select password from userInfo where userId= ‘”+userId+”’”;   
  11. try{   
  12.     …   
  13.      //JDBC调用   
  14.      s.executeQuery(sql);   
  15.     …   
  16.    }catch(SQLException ex){   
  17.       throw new DataAccessException(“数据库查询失败”+sql,ex);   
  18.    }   
  19. }   
  20. }   
 
定义一个checked的业务异常,让业务层的接口的所有方法都声明抛出Checked异常.
 
java 代码
  1. public class BusinessException extends Exception{   
  2.  …..   
  3. }   
  4.     
  5. public interface UserManager{   
  6.    public Userinfo copyUserInfo(Userinfo user)throws BusinessException{   
  7.       Userinfo newUser = null;   
  8.       try{   
  9.         newUser = (Userinfo)user.clone();   
  10. }catch(CloneNotSupportedException ex){   
  11.  throw new BusinessException(“不支持clone方法:”+Userinfo.class.getName(),ex);   
  12. }   
  13.  }   
  14. }  
 
J2ee表示层应该是一个很薄的层,主要的功能为:获得页面请求,把页面的参数组装成POJO对象,调用相应的业务方法,然后进行页面转发,把相应的业务数据呈现给页面。表示层需要注意一个问题,表示层需要对数据的合法性进行校验,比如某些录入域不能为空,字符长度校验等。
J2ee从页面所有传给后台的参数都是字符型的,如果要求输入数值或日期类型的参数时,必须把字符值转换为相应的数值或日期值。
如果表示层代码校验参数不合法时,应该返回到原始页面,让用户重新录入数据,并提示相关的错误信息。
 
通常把一个从页面传来的参数转换为数值,我们可以看到这样的代码
java 代码
  1. ModeAndView handleRequest(HttpServletRequest request,HttpServletResponse response)throws Exception{   
  2.    String ageStr = request.getParameter(“age”);   
  3.    int age = Integer.parse(ageStr);   
  4.    …………   
  5.     
  6.  String birthDayStr = request.getParameter(“birthDay”);   
  7. SimpleDateFormat format = new SimpleDateFormat(“MM/dd/yyyy”);   
  8. Date birthDay = format.parse(birthDayStr);   
  9.     
  10. }   
 
上面的代码应该经常见到,但是当用户从页面录入一个不能转换为整型的字符或一个错误的日期值。
Integer.parse()方法被抛出一个NumberFormatException的unChecked异常。但是这个异常绝对不是一个致命的异常,一般当用户在页面的录入域录入的值不合法时,我们应该提示用户进行重新录入。但是一旦抛出unchecked异常,就没有重试的机会了。像这样的代码造成大量的异常信息显示到页面。使我们的系统看起来非常的脆弱。
同样,SimpleDateFormat.parse()方法也会抛出ParseException的unChecked异常。
这种情况我们都应该捕获这些unChecked异常,并给提示用户重新录入。
java 代码
  1. ModeAndView handleRequest(HttpServletRequest request,HttpServletResponse response)throws Exception{   
  2.    String ageStr = request.getParameter(“age”);   
  3. String birthDayStr = request.getParameter(“birthDay”);   
  4.    int age = 0;   
  5.  Date birthDay = null;   
  6. try{   
  7. age=Integer.parse(ageStr);   
  8.    }catch(NumberFormatException ex){   
  9.      error.reject(“age”,”不是合法的整数值”);   
  10.    }   
  11.    …………   
  12.     
  13.  try{   
  14. SimpleDateFormat format = new SimpleDateFormat(“MM/dd/yyyy”);   
  15.  birthDay = format.parse(birthDayStr);   
  16. }catch(ParseException ex){   
  17.  error.reject(“birthDay”,”不是合法的日期,请录入’MM/dd/yyy’格式的日期”);   
  18. }   
  19.     
  20. }  
在表示层一定要弄清楚调用方法的是否会抛出unChecked异常,什么情况下会抛出这些异常,并作出正确的处理。
在表示层调用系统的业务方法,一般情况下是无需要捕获异常的。如果调用的业务方法抛出的异常相当于第二个返回值时,在这种情况下是需要捕获
分享到:
评论
58 楼 mengfei86 2014-08-07  
你们讨论的时候我刚上大学,。。。。、、现在都过去好多年了,。有什么新的体会,新的想法呢,。我在做一个项目,异常处理那想好好弄弄,。
57 楼 realorg 2007-09-27  
楼主,你的异常处理好经典啊~!

受益匪浅啊~!

你的图片也很吸引我们的眼球~!:)
56 楼 klyuan 2007-07-16  
jerrycong 写道
引用

一般地,我们需要定义一个unChecked异常,让集成层接口的所有方法都声明抛出这unChecked异常。
java 代码
public DataAccessException extends RuntimeException{   
……   
}   
public interface UserDao{   
public String getPassword(String userId)throws DataAccessException;   
}   
    
public class UserDaoImpl implements UserDAO{   
public String getPassword(String userId)throws DataAccessException{   
String sql = “select password from userInfo where userId= ‘”+userId+”’”;   
try{   
    …   
     //JDBC调用   
     s.executeQuery(sql);   
    …   
   }catch(SQLException ex){   
      throw new DataAccessException(“数据库查询失败”+sql,ex);   
   }   
}   
}   

定义一个checked的业务异常,让业务层的接口的所有方法都声明抛出unChecked异常.

java 代码
public class BusinessException extends Exception{   
…..   
}   
    
public interface UserManager{   
   public Userinfo copyUserInfo(Userinfo user)throws BusinessException{   
      Userinfo newUser = null;   
      try{   
        newUser = (Userinfo)user.clone();   
}catch(CloneNotSupportedException ex){   
throw new BusinessException(“不支持clone方法:”+Userinfo.class.getName(),ex);   
}   
}   
}  


不好意思,两个问题
1) 接口UserDao应该可以把throws DataAccessException 拿掉
2) 定义一个checked的业务异常,让业务层的接口的所有方法都声明抛出unChecked异常.

这句话对么?定义了BusinessException这个checked异常,public Userinfo copyUserInfo(Userinfo user)throws BusinessException,让业务层的接口的所有方法都声明抛出unChecked异常怎么理解?

望指教


1)那是不对滴。为什么要让Dao抛出unChecked异常呢?就是进行一次封装!让上层调用者自己决定处理dao的异常


2)如果让业务方法都抛出unChecked异常,业务方法是我们最关心的。最需要去处理的。所以强制处理
55 楼 jwnest 2007-07-16  
我的想法:
1/ 根据系统的分层,每层自定义一个unchecked exception, exception里面只包含简单的message信息即可, 这样每层实现时,只需要抛出本层定义的exception并提供信息就可以了;
2/ 还是根据系统分层,高层在调用底层的api时,一定要捕获底层定义的这个exception(不过推荐是catch Exception()),并根据本层的logic决定是继续抛出本层的exception还是进行其他处理;
3/ 提供一个util方法可以拿到root exception的message,这样可以保证即使进行多次包装后,也能得到最初抛出exception的信息;
4/ checked exception能不用就不用,除非有业务逻辑需要通过exception来实现不同的流程(这种情况通常也是可以避免的),还有就是涉及到资源的情况,有可能必须使用checked exception,不过一般来说,这种情况都可以限制在本层内部,通过catch and rethrow我们自定义的异常来解决,只是需要注意在finally里面把资源释放掉.

曾经使用别人提供的api,里面会抛出一个自定义checked exception,可是我这边的logic非常复杂,涉及到3到4层的调用,如果每层都try catch的话....最终只能将这个checked exception包装成一个unchecked exception...世界清净了

一般来说,不管是抛出何种异常,就代表logic已经发生错误,而且基本不太可能恢复,所以checked exception用处真的不大.

个人观点,欢迎大家讨论.

54 楼 jerrycong 2007-07-15  
引用

一般地,我们需要定义一个unChecked异常,让集成层接口的所有方法都声明抛出这unChecked异常。
java 代码
public DataAccessException extends RuntimeException{   
……   
}   
public interface UserDao{   
public String getPassword(String userId)throws DataAccessException;   
}   
    
public class UserDaoImpl implements UserDAO{   
public String getPassword(String userId)throws DataAccessException{   
String sql = “select password from userInfo where userId= ‘”+userId+”’”;   
try{   
    …   
     //JDBC调用   
     s.executeQuery(sql);   
    …   
   }catch(SQLException ex){   
      throw new DataAccessException(“数据库查询失败”+sql,ex);   
   }   
}   
}   

定义一个checked的业务异常,让业务层的接口的所有方法都声明抛出unChecked异常.

java 代码
public class BusinessException extends Exception{   
…..   
}   
    
public interface UserManager{   
   public Userinfo copyUserInfo(Userinfo user)throws BusinessException{   
      Userinfo newUser = null;   
      try{   
        newUser = (Userinfo)user.clone();   
}catch(CloneNotSupportedException ex){   
throw new BusinessException(“不支持clone方法:”+Userinfo.class.getName(),ex);   
}   
}   
}  


不好意思,两个问题
1) 接口UserDao应该可以把throws DataAccessException 拿掉
2) 定义一个checked的业务异常,让业务层的接口的所有方法都声明抛出unChecked异常.

这句话对么?定义了BusinessException这个checked异常,public Userinfo copyUserInfo(Userinfo user)throws BusinessException,让业务层的接口的所有方法都声明抛出unChecked异常怎么理解?

望指教
53 楼 jiakechong 2007-07-13  
不错,谢谢
52 楼 klyuan 2007-06-08  
Godlikeme 写道
klyuan 写道
fhjxp 写道
klyuan 写道

返回值,这没有什么难以理解的啦!!
当方法出现几种逻辑时,有时用方法的返回值无法描述,这时可以用一个异常信息来代表返回结果!

唉,可能我还是没有说清楚!!我得去翻以前的程序,把例子弄出来

这种做法应该尽量避免,最近项目组里写一个根据将xml文件导入数据库,在导入之前需要验证xml的合法性,当xml不合法的时候,想告诉用户一个比较详细的信息:比如在哪行哪列出错了,就将这些信息写入异常中抛出来,这算是一个返回结果吧,勉强可以接受,大概这样:
    try{
      check();
      import();
      forward(sucess);
    }catch(Exception,e){
      forward(error,e)
    }



一般情况是不会这样做的!!!
我遇到这样的一个需求!
项目之间的关系有三种:前,后,无。
需要判断所有的项目间不能存在循环路径
a -> b->c->a
这就是循环路径了!
我用一个图实现检查是否存在循环路径,并且需要记录下这个循环路径。
需求仅要找出第一个循环路径即可,就不用往下找了
思路:从任一个点出发,如果找到它邻节点为第一个出发点时,那么就是循环路径。
当然是使用递归来实现的,因为需要记录循环的路径,所以比较麻烦的。一开始我是使用返回值!
这样它会记录的路径其实是一个倒置的路径。但中间还会出很多问题,这点我就不详细说了!
后来我干脆采用异常的方式来处理。
从任意一点往下找,当任一节点的邻节点为第第一个出发点时,我就抛出异常
			if(vertexIndex == firstVertexIndex){
			throw new CycleException("存在环路!");
			}

这也是最不可能出错和效率最高的方法了!
上级调用代码
			try {
		    recordList.add(this.vertexList.get(vertexIndex));
		     int nextVertex = findHasNextVertex(vertexIndex,vertexIndex,recordList);
			}
			catch(CycleException ex) {
				return recordList;
			}


但是千万不要学这种方式!
这有时是不得已而为之的!


不讨论异常处理的方式。
有向图存在环不是这么检查的吧?
每次搜索 从任一初始点出发,广度搜索,只要访问到访问过得点就认为存在环。


我这里只是一点点代码,我不可能把所有的贴出来吧!!!!
深度还是广度遍历都是可以的嘛!
51 楼 Godlikeme 2007-06-08  
ithero 写道
这是在JavaEye中对Exception的讨论较有深度的一篇贴子.受用了


没看过中文版,j2ee design and development E版里面有比较详细的说明,
50 楼 Godlikeme 2007-06-08  
klyuan 写道
fhjxp 写道
klyuan 写道

返回值,这没有什么难以理解的啦!!
当方法出现几种逻辑时,有时用方法的返回值无法描述,这时可以用一个异常信息来代表返回结果!

唉,可能我还是没有说清楚!!我得去翻以前的程序,把例子弄出来

这种做法应该尽量避免,最近项目组里写一个根据将xml文件导入数据库,在导入之前需要验证xml的合法性,当xml不合法的时候,想告诉用户一个比较详细的信息:比如在哪行哪列出错了,就将这些信息写入异常中抛出来,这算是一个返回结果吧,勉强可以接受,大概这样:
    try{
      check();
      import();
      forward(sucess);
    }catch(Exception,e){
      forward(error,e)
    }



一般情况是不会这样做的!!!
我遇到这样的一个需求!
项目之间的关系有三种:前,后,无。
需要判断所有的项目间不能存在循环路径
a -> b->c->a
这就是循环路径了!
我用一个图实现检查是否存在循环路径,并且需要记录下这个循环路径。
需求仅要找出第一个循环路径即可,就不用往下找了
思路:从任一个点出发,如果找到它邻节点为第一个出发点时,那么就是循环路径。
当然是使用递归来实现的,因为需要记录循环的路径,所以比较麻烦的。一开始我是使用返回值!
这样它会记录的路径其实是一个倒置的路径。但中间还会出很多问题,这点我就不详细说了!
后来我干脆采用异常的方式来处理。
从任意一点往下找,当任一节点的邻节点为第第一个出发点时,我就抛出异常
			if(vertexIndex == firstVertexIndex){
			throw new CycleException("存在环路!");
			}

这也是最不可能出错和效率最高的方法了!
上级调用代码
			try {
		    recordList.add(this.vertexList.get(vertexIndex));
		     int nextVertex = findHasNextVertex(vertexIndex,vertexIndex,recordList);
			}
			catch(CycleException ex) {
				return recordList;
			}


但是千万不要学这种方式!
这有时是不得已而为之的!


不讨论异常处理的方式。
有向图存在环不是这么检查的吧?
每次搜索 从任一初始点出发,广度搜索,只要访问到访问过得点就认为存在环。
49 楼 klyuan 2007-06-08  
<br/>
<strong>javastudy 写道:</strong><br/>
<div class='quote_div'><br/>
<div class='quote_div'>
<div style='margin: 0cm 0cm 0pt 18pt;'>
<div>所有继承java.lang.Exception 的异常都属于checked异常。所有继承java.lang.RuntimeException的异常都属于</div>
<div/>
<div>难道java.lang.RuntimeException不是继承java.lang.Exception吗</div>
</div>
</div>
</div>
<br/>
<br/>
<br/>
<br/>
48 楼 ithero 2007-06-07  
这是在JavaEye中对Exception的讨论较有深度的一篇贴子.受用了
47 楼 klyuan 2007-06-07  
fhjxp 写道
klyuan 写道

返回值,这没有什么难以理解的啦!!
当方法出现几种逻辑时,有时用方法的返回值无法描述,这时可以用一个异常信息来代表返回结果!

唉,可能我还是没有说清楚!!我得去翻以前的程序,把例子弄出来

这种做法应该尽量避免,最近项目组里写一个根据将xml文件导入数据库,在导入之前需要验证xml的合法性,当xml不合法的时候,想告诉用户一个比较详细的信息:比如在哪行哪列出错了,就将这些信息写入异常中抛出来,这算是一个返回结果吧,勉强可以接受,大概这样:
    try{
      check();
      import();
      forward(sucess);
    }catch(Exception,e){
      forward(error,e)
    }



一般情况是不会这样做的!!!
我遇到这样的一个需求!
项目之间的关系有三种:前,后,无。
需要判断所有的项目间不能存在循环路径
a -> b->c->a
这就是循环路径了!
我用一个图实现检查是否存在循环路径,并且需要记录下这个循环路径。
需求仅要找出第一个循环路径即可,就不用往下找了
思路:从任一个点出发,如果找到它邻节点为第一个出发点时,那么就是循环路径。
当然是使用递归来实现的,因为需要记录循环的路径,所以比较麻烦的。一开始我是使用返回值!
这样它会记录的路径其实是一个倒置的路径。但中间还会出很多问题,这点我就不详细说了!
后来我干脆采用异常的方式来处理。
从任意一点往下找,当任一节点的邻节点为第第一个出发点时,我就抛出异常
			if(vertexIndex == firstVertexIndex){
			throw new CycleException("存在环路!");
			}

这也是最不可能出错和效率最高的方法了!
上级调用代码
			try {
		    recordList.add(this.vertexList.get(vertexIndex));
		     int nextVertex = findHasNextVertex(vertexIndex,vertexIndex,recordList);
			}
			catch(CycleException ex) {
				return recordList;
			}


但是千万不要学这种方式!
这有时是不得已而为之的!
46 楼 klyuan 2007-06-07  
抛出异常的爱 写道
fhjxp 写道
抛出异常的爱 写道
如果对异常有一定的规律性可以用spring来作异常处理,
减少恶心的try catch 块。。。。
(这样用checked的理由又多了一点点)

这怎么就成为了checked的理由呢?如果用Spring,也就是说异常交由Spring来处理,方法调用更不用知道有异常的存在了,unchecked不是更好么。透明到底


事实上spring的用法都是unchecked
但是我还是认为spring 能带来checked的用法变革


这也不竟然吧!!只有严重的错误才会抛unchecked异常!
45 楼 fhjxp 2007-06-07  
抛出异常的爱 写道
fhjxp 写道
抛出异常的爱 写道
如果对异常有一定的规律性可以用spring来作异常处理,
减少恶心的try catch 块。。。。
(这样用checked的理由又多了一点点)

这怎么就成为了checked的理由呢?如果用Spring,也就是说异常交由Spring来处理,方法调用更不用知道有异常的存在了,unchecked不是更好么。透明到底


事实上spring的用法都是unchecked
但是我还是认为spring 能带来checked的用法变革

能说一下原因么?实在不理解
44 楼 fhjxp 2007-06-07  
klyuan 写道

返回值,这没有什么难以理解的啦!!
当方法出现几种逻辑时,有时用方法的返回值无法描述,这时可以用一个异常信息来代表返回结果!

唉,可能我还是没有说清楚!!我得去翻以前的程序,把例子弄出来

这种做法应该尽量避免,最近项目组里写一个根据将xml文件导入数据库,在导入之前需要验证xml的合法性,当xml不合法的时候,想告诉用户一个比较详细的信息:比如在哪行哪列出错了,就将这些信息写入异常中抛出来,这算是一个返回结果吧,勉强可以接受,大概这样:
    try{
      check();
      import();
      forward(sucess);
    }catch(Exception,e){
      forward(error,e)
    }

43 楼 抛出异常的爱 2007-06-07  
fhjxp 写道
抛出异常的爱 写道
如果对异常有一定的规律性可以用spring来作异常处理,
减少恶心的try catch 块。。。。
(这样用checked的理由又多了一点点)

这怎么就成为了checked的理由呢?如果用Spring,也就是说异常交由Spring来处理,方法调用更不用知道有异常的存在了,unchecked不是更好么。透明到底


事实上spring的用法都是unchecked
但是我还是认为spring 能带来checked的用法变革
42 楼 fhjxp 2007-06-07  
抛出异常的爱 写道
如果对异常有一定的规律性可以用spring来作异常处理,
减少恶心的try catch 块。。。。
(这样用checked的理由又多了一点点)

这怎么就成为了checked的理由呢?如果用Spring,也就是说异常交由Spring来处理,方法调用更不用知道有异常的存在了,unchecked不是更好么。透明到底
41 楼 steven_cheng 2007-06-07  
<p>最近刚好作了一个产品的异常处理规范,把我做的也拿出来晒晒,和大家讨论一下。</p>
<p>1、CheckException or UnCheckedException</p>
<p>个人倾向用UnCheckedException。我见过的最多的处理异常的代码就是记录日志或转换后抛出<img src='/javascripts/fckeditor/editor/images/smiley/msn/teeth_smile.gif' alt=''/>,好像做其他操作的少之又少。我以前还见过有人不管三七二十一,抓到什么抛什么,结果一个接口抛出了3-5种CheckException。别扭啊,呵呵。</p>
<p>当然,最大的缺陷就是对接口调用者的使用。至少UnCheckedException可以让接口调用者选择catch还是不catch。</p>
<p>因为这是一个遗留系统,都使用了CheckedException,不过好在使用的比较规范,没有太大麻烦。</p>
<p>2、异常信息</p>
<p>因为开发者众多,异常信息五花八门,有中文的有英文的,有简单的,有复杂的。散落在各个类里,修改起来很麻烦。</p>
<p>我的处理办法是,定义异常码,异常信息和异常码一一对应,定义在properties文件里,抛出异常的地方只引用异常码。这样,如果需要修改异常信息,只要修改properties文件重新打包即可。异常码分为原因码和位置码。位置码一般用在业务逻辑类里。比如一般用到的Facad模式,可能一个接口定义了n个方法,每个方法都抛出XXXBusinessException(XXX用于区分业务子包),抛出的异常码在代码里顺序定义即可。原因码表示某类异常,比如SQLException引起的异常都为8000。</p>
<p>异常码中原因码按包、类、接口定义,比如:前两位表示一级子包,接下来两位留给二级子包,接下来两位表示类,最后3位表示方法。</p>
<p>异常信息如果需要,可以保留现场信息。比如:“<font>用户[abc]已存在”。这样的信息就比“<font>用户已存在”明确。这个功能可以通过<font>java.text.MessageFormat实现。</font></font></font></p>
<p>3、异常的链式抛出</p>
<p>即,在调用底层接口时捕获到异常,需要转成其他的异常抛出时<font size='1'>,<font>使用带Throwable的构造器。这样可以保留最原始的出错信息。</font></font></p>
<p><font size='1'>异常基类代码:</font></p>
<div class='code_title'>java 代码</div>
<div class='dp-highlighter'>
<div class='bar'/>
<ol class='dp-j'>
    <li class='alt'><span><span class='keyword'>public</span><span> </span><span class='keyword'>class</span><span> BaseException </span><span class='keyword'>extends</span><span> Exception {   </span></span></li>
    <li class=''><span>       </span></li>
    <li class='alt'><span>       </span></li>
    <li class=''><span>    </span><span class='keyword'>protected</span><span> </span><span class='keyword'>long</span><span> errorCode;   </span></li>
    <li class='alt'><span>       </span></li>
    <li class=''><span>       </span></li>
    <li class='alt'><span>    </span><span class='keyword'>protected</span><span> String[] args;   </span></li>
    <li class=''><span>  </span></li>
    <li class='alt'><span>    </span><span class='comment'>/** </span> </li>
    <li class=''><span><span class='comment'>     * @param errorCode </span> </span></li>
    <li class='alt'><span><span class='comment'>     */</span><span>  </span></span></li>
    <li class=''><span>    </span><span class='keyword'>public</span><span> BaseException(</span><span class='keyword'>long</span><span> errorCode) {   </span></li>
    <li class='alt'><span>        </span><span class='keyword'>super</span><span>();   </span></li>
    <li class=''><span>        </span><span class='keyword'>this</span><span>.errorCode = errorCode;   </span></li>
    <li class='alt'><span>    }   </span></li>
    <li class=''><span>       </span></li>
    <li class='alt'><span>    </span><span class='comment'>/** </span> </li>
    <li class=''><span><span class='comment'>     * @param errorCode </span> </span></li>
    <li class='alt'><span><span class='comment'>     * @param cause </span> </span></li>
    <li class=''><span><span class='comment'>     */</span><span>  </span></span></li>
    <li class='alt'><span>    </span><span class='keyword'>public</span><span> BaseException(</span><span class='keyword'>long</span><span> errorCode,Throwable cause) {   </span></li>
    <li class=''><span>        </span><span class='keyword'>super</span><span>(cause);   </span></li>
    <li class='alt'><span>        </span><span class='keyword'>this</span><span>.errorCode = errorCode;   </span></li>
    <li class=''><span>    }   </span></li>
    <li class='alt'><span>       </span></li>
    <li class=''><span>    </span><span class='comment'>/** </span> </li>
    <li class='alt'><span><span class='comment'>     * @param errorCode </span> </span></li>
    <li class=''><span><span class='comment'>     * @param cause </span> </span></li>
    <li class='alt'><span><span class='comment'>     * @param args @see {@link java.text.MessageFormat#format(Object)} </span> </span></li>
    <li class=''><span><span class='comment'>     */</span><span>  </span></span></li>
    <li class='alt'><span>    </span><span class='keyword'>public</span><span> BaseException(</span><span class='keyword'>long</span><span> errorCode,Throwable cause,String[] args) {   </span></li>
    <li class=''><span>        </span><span class='keyword'>super</span><span>(cause);   </span></li>
    <li class='alt'><span>        </span><span class='keyword'>this</span><span>.errorCode = errorCode;   </span></li>
    <li class=''><span>        </span><span class='keyword'>this</span><span>.args = args;   </span></li>
    <li class='alt'><span>    }   </span></li>
    <li class=''><span>       </span></li>
    <li class='alt'><span>    </span><span class='comment'>/* (non-Javadoc) </span> </li>
    <li class=''><span><span class='comment'>     * @see java.lang.Throwable#getMessage() </span> </span></li>
    <li class='alt'><span><span class='comment'>     */</span><span>  </span></span></li>
    <li class=''><span>    </span><span class='keyword'>public</span><span> String getMessage() {   </span></li>
    <li class='alt'><span>        String message = </span><span class='string'>""</span><span>;   </span></li>
    <li class=''><span>        </span><span class='keyword'>if</span><span> (</span><span class='keyword'>this</span><span>.args == </span><span class='keyword'>null</span><span> || </span><span class='keyword'>this</span><span>.args.length == </span><span class='number'>0</span><span>) {   </span></li>
    <li class='alt'><span>            message = MessageSource.getInstance().resolveCodeWithoutArguments(   </span></li>
    <li class=''><span>                    </span><span class='keyword'>this</span><span>.errorCode);   </span></li>
    <li class='alt'><span>        } </span><span class='keyword'>else</span><span> {   </span></li>
    <li class=''><span>            message = MessageSource.getInstance().resolveCode(</span><span class='keyword'>this</span><span>.errorCode)   </span></li>
    <li class='alt'><span>                    .format(</span><span class='keyword'>this</span><span>.args);   </span></li>
    <li class=''><span>        }   </span></li>
    <li class='alt'><span>  </span></li>
    <li class=''><span>        </span><span class='keyword'>return</span><span> </span><span class='keyword'>this</span><span>.errorCode+</span><span class='string'>":"</span><span>+message;   </span></li>
    <li class='alt'><span>    }   </span></li>
    <li class=''><span>  </span></li>
    <li class='alt'><span>    </span><span class='comment'>/** </span> </li>
    <li class=''><span><span class='comment'>     * @return the errorCode </span> </span></li>
    <li class='alt'><span><span class='comment'>     */</span><span>  </span></span></li>
    <li class=''><span>    </span><span class='keyword'>public</span><span> </span><span class='keyword'>long</span><span> getErrorCode() {   </span></li>
    <li class='alt'><span>        </span><span class='keyword'>return</span><span> errorCode;   </span></li>
    <li class=''><span>    }   </span></li>
    <li class='alt'><span>  </span></li>
    <li class=''><span>    </span><span class='comment'>/** </span> </li>
    <li class='alt'><span><span class='comment'>     * @return the args </span> </span></li>
    <li class=''><span><span class='comment'>     */</span><span>  </span></span></li>
    <li class='alt'><span>    </span><span class='keyword'>public</span><span> String[] getArgs() {   </span></li>
    <li class=''><span>        </span><span class='keyword'>return</span><span> args;   </span></li>
    <li class='alt'><span>    }   </span></li>
    <li class=''><span>  </span></li>
    <li class='alt'><span>}  </span></li>
</ol>
</div>
<p>其中:MessageSource这个类就是根据是否有现场信息,分别处理,得到完整异常信息表述字符串。</p>
<p>关于主贴中嵌套打印的部分,从JDK1.4开始,Throwable就是嵌套打印的,所以不必再覆盖那几个方法了。</p>
<p>现在假使,有AException 和BException,都从BaseException继承。在方法里,我们捕获了AException,需要转换成BException抛出,这时候我们就非常希望能直接用AException的信息(errorCode和args)。所以,如果再来这样一个构造器似乎更好:</p>
<div class='code_title'>java 代码</div>
<div class='dp-highlighter'>
<div class='bar'/>
<ol class='dp-j'>
    <li class='alt'><span><span class='keyword'>public</span><span> BaseException(BaseException cause){   </span></span></li>
    <li class=''><span>    </span><span class='keyword'>this</span><span>.errorCode = cause.getErrorCode();   </span></li>
    <li class='alt'><span>    </span><span class='keyword'>this</span><span>.args = cause.getArgs();   </span></li>
    <li class=''><span>}  </span></li>
</ol>
</div>
<p>但是,因为Exception有一个构造器:<font>public Exception(Throwable cause),所以这样的构造器就是<font><strong>重载(overload)</strong>,而不是<font><strong>覆盖(Override)</strong>。重载,入参又是父子类关系,这样的方法很容易混淆,所以就没有提供。</font></font></font></p>
<p>我按照这个异常处理规范,花了两三天时间把代码重构了一遍。似乎用起来挺好使<img src='/javascripts/fckeditor/editor/images/smiley/msn/teeth_smile.gif' alt=''/></p>
40 楼 klyuan 2007-06-07  
抛出异常的爱 写道
改的好快。。。
正想问有什么东西说错呢。


我一直想不出怎么简化这文章了!!
39 楼 抛出异常的爱 2007-06-06  
改的好快。。。
正想问有什么东西说错呢。

相关推荐

    J2EE项目异常处理的几种方案

    J2EE项目异常处理的几种方案 内有代码

    J2EE项目中统一异常处理源码

    J2EE项目中统一异常处理,14类异常的自定义分析,支持dao层异常原因的返回

    J2EE专业项目实例开发(2)

    本书是学习J2EE编程的优秀参考书,主要包括以下内容:第一部分概述了有关J2EE编程的重要概念,如applet的创建、布局管理器和事件处理、异常处理和线程、存储数据和创建网络应用程序、RMI和CORBA;第二部分介绍J2EE的...

    为J2EE定制一个用来处理错误的异常处理框架

    回顾一下上一个J2EE工程,是否遇到过类似错误没有记 入日志或者被多次记录的情况?是否只是因为在某处代码吃 掉了异常导致你花费无数次时间...这篇文章为你提供了在J2EE项目中通过使用错误处理框架使用一些策略的基础。

    springmvc 异常统一处理的三种方式详解.docx

    在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大...

    J2EE专业项目实例开发(3)

    本书是学习J2EE编程的优秀参考书,主要包括以下内容:第一部分概述了有关J2EE编程的重要概念,如applet的创建、布局管理器和事件处理、异常处理和线程、存储数据和创建网络应用程序、RMI和CORBA;第二部分介绍J2EE的...

    J2EE专业项目实例开发(1)

    本书是学习J2EE编程的优秀参考书,主要包括以下内容:第一部分概述了有关J2EE编程的重要概念,如applet的创建、布局管理器和事件处理、异常处理和线程、存储数据和创建网络应用程序、RMI和CORBA;第二部分介绍J2EE的...

    J2EE专业项目实例开发(4)

    本书是学习J2EE编程的优秀参考书,主要包括以下内容:第一部分概述了有关J2EE编程的重要概念,如applet的创建、布局管理器和事件处理、异常处理和线程、存储数据和创建网络应用程序、RMI和CORBA;第二部分介绍J2EE的...

    Java Web项目整体异常处理机制

    在实际的j2ee项目中,系统内部难免会出现一些异常,如果把异常放任不管直接打印到浏览器可能会让用户感觉莫名其妙,也有可能让某些用户找到破解系统的方法。  出来工作一年时间了,我也大概对异常处理有了一些...

    java web项目整体异常处理机制.doc

    实际的j2ee项目中,系统内部难免会出现一些异常,如果把异常放任不管直接打印到浏览器可能会让用户感觉莫名其妙,也有可能让某些用户找到破解系统的方法。

    J2EE中文版指南 CHM格式 带全文检索

    异常处理 94 第6章 CMP的例子 96 一 RosterApp应用概述 97 二 layerEJB代码分析 97 实体Bean类 98 CMP和BMP实现实体Bean的代码比较 98 访问(get和set)方法 98 持久性字段的访问方法 99 关系字段的访问方法 99 ...

    《程序天下:J2EE整合详解与典型案例》光盘源码

    8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 9.3.1 添加CVS资源库 9.3.2 提交...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (1)

    8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 9.3.1 添加CVS资源库 9.3.2 提交...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (3)

    8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 9.3.1 添加CVS资源库 9.3.2 提交...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (2)

    8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 9.3.1 添加CVS资源库 9.3.2 提交...

    Xiaoniu-net:小牛网农资农产品销售平台 —— 一个前后端分离的J2EE项目

    小牛网农资农产品销售平台 —— 一个前后端分离的J2EE项目。 项目描述: 平台运作是以农民为主体构建三角锥型合作链条。 农资企业:审核入驻—&gt;发布农资产品信息。 农民:注册—&gt;下单农资、发布农产品信息。 农产品...

    J2EE开发全程实录(JAVA项目开发)

    8.1.1 异常处理的方式... 135 8.1.2 为异常“脱皮”... 140 8.1.3 枚举异常... 141 8.1.4 异常处理器... 146 8.2 工具类... 147 8.2.1 枚举... 147 8.2.2 资源管理工具类... 149 8.2.3 DateUtils. 149 8.2.4 ...

    J2EE简易课程教学PPT

    Hibernate查询 Hibernate基础 Hibernate数据关联 javaweb开发技术 Struts标记库 Struts表单验证及异常处理 Struts国际化与Validator验证框架 Struts配置文件 Struts入门 项目实践-名片管理系统

    高级Java软件架构师学习计划

    异常处理与事件响应 Java基础类库与中期项目实战 Java多线程编程、网络编程 项目实战 J2EE中级 数据库基础与linux操作系统 JDBC程序开发 JavaEE基础 JSP、SERVLET、JSTL 和 EL JavaBean/EJB MVC 设计模式与中期项目...

Global site tag (gtag.js) - Google Analytics