`
czpsailer
  • 浏览: 10435 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Java 接口的异常设计疑惑

    博客分类:
  • OO
阅读更多

疑惑1:在设计接口的时,对于接口方法何时需要声明抛出受检异常或者说所有的接口方法最后都声明抛出受检异常?
      
       public interface xx{
              public void method();
       }

       public interface xx{
             public void method() throws Exception;
       }

 

      
      
疑惑2:如果需要声明抛出受检异常,那是抛出一个抽象的异常呢;还是抛出多个具体的异常?

       a,抛出具体异常:

         public interface xx{
               public void method() throws SpecificException1,SpecificException2,...;
         }

         ps:如果要抛出具体异常那就要考虑全部可能的实现类会抛出的异常,我想这样几乎不可能吧。

       b,抛出抽象的异常。如果是这样那是抛出自定义抽象异常呢,还是直接抛出Exception?

         自定义抽象异常:

           public interface xx{
                public void method() throws CustomAbstractException;
           }

         直接抛出Exception:

           public interface xx{
                public void method() throws Exception;

           }

 

     大家说说看到底如何做比较合理?理由是什么?

 

分享到:
评论
26 楼 282912533 2009-11-18  
如果是专业接口 , 设计上有抛出异常比较好 , 但通用接口就最好不要了 ~
比方执行SQL的接口 , 抛出 SQLException , 但作为通用接口就没什么必要了 , 因为可能涉及到其他东西 .
好比 , 通用的电源插座 , 不会在每个插座都标记上会漏电 , 小心防火之类的 .
但专用燃气热水器接口会提示 , 只能应用于天然气 .
这些列举都是最简单的面向对象 .
25 楼 池中物 2009-11-18  
如果业务方法只可能抛出某个特定的异常那就声明为抛出那个具体异常咯。
24 楼 qinhanbin 2009-11-17  
这个问题就好比吃饭是用叉子和筷子哪个好?见仁见智,接口作为一种规范,它所定义的范畴是要大于和等于业务范畴的,在接口中显式的抛出具体的异常是不太合适的,但划分的粒度过大又导致业务异常的分类复杂,所以尽量采取倒三角型的输出模式,由上层调用者来细分异常,所以无论是两层、三层或四层结构,其对异常的声明都是不尽相同的,越到底层,接口的声明尽量宽泛,由于运行时异常无须显式的捕获和抛出,所以推荐将底层的异常封装成相应的系统异常抛出,同时对业务层的各种业务异常和其他异常分类捕获,这样不仅代码中减少try..catch块,而且在各层的接口声明上更加松耦合,层与层之间的层次更加宽松,不会在重构时受层层之间的约束,具体问题具体分析,最终还得由决策者来判断
23 楼 czpsailer 2009-11-13  
woaiwofengkuang 写道
异常的定义,我觉不能离开系统的业务范畴。接中的作用就是定义一个业务功能的入口,下面有可能接用好几个方法来完成这个业务功能。可能根据具体业务实际情况来定义可能出现的一些不符合业务规则的异常。对于一个其它的异常如:集合为空,除非和业务规则有关系,要提示错误信息给用户看要抛出异常外其它的个人感觉直接抛出一个Exception来就行。


如果是业务性的接口,那么接口的异常就表示了业务的异常流;如果是通用的接口(比如框架中的接口),这样的接口我觉得它的业务性就比较不明确了,随着你的不同运用它有不同的业务性,它过多是作为一种机制来使用的,这样接口的定义异常就如我上面的说的那样就仁者见仁了。
22 楼 woaiwofengkuang 2009-11-13  
异常的定义,我觉不能离开系统的业务范畴。接中的作用就是定义一个业务功能的入口,下面有可能接用好几个方法来完成这个业务功能。可能根据具体业务实际情况来定义可能出现的一些不符合业务规则的异常。对于一个其它的异常如:集合为空,除非和业务规则有关系,要提示错误信息给用户看要抛出异常外其它的个人感觉直接抛出一个Exception来就行。
21 楼 zhxing 2009-11-13  
因为异常处理的开销比较大??
这个怎么理解?好像虚拟机处理的时候都差不多的吧,遇到一个异常就停止执行,返回处理。。。

还是听听大虾们怎么理解...
20 楼 pipilu 2009-11-12  
是啊,楼上,声明成通用的,其实也是需要调用者参考文档来处理的。不然他捕获了异常也没啥用。
19 楼 czpsailer 2009-11-12  
pipilu 写道
joachimz 写道
pipilu 写道
czpsailer 写道
在接口有多个不同的实现类时,不同的实现又可能抛出不同的异常,这样就无法在接口声明中将这些具体异常全部声明出来了,这时候使用一个抽象的异常就比较可行了。可是如果这样的话,我觉的使用接口的地方,就无法明确到底会出现哪些具体的异常了。这样貌似异常的使用原则(尽量指定具体的异常)有些相违背了。


这个接口本身都不知道会抛出什么异常,为什么还要向上抛出呢?(除非是上层调用可以处理的异常),自己都不确定的,上一层更没法知道怎么处理你这些异常了。不如就在本层处理,或者转成运行时异常。

这个是在稳定性与灵活性上去权衡:有一个基础类,可以保持接口稳定,让不同使用场景自行去约定异常。只有通用接口才有这样的需求,一般是框架类。具体子类实现的时候,还需要与使用者自行去约定异常。

一般业务逻辑中,专用接口,则需要详细定义异常。


有道理。
这种情况下,我倾向于交由实现类来自行决定抛出运行时异常,使用接口的开发人员通过阅读文档来了解实现类可能会抛出的异常。避免异常声明给调用者带来负担。


这样其实有个问题,因为你无法阅读到所有的实现类的API文档和无法很好的预期运行是客户端会调用的那个实现类。

例如:当前已知有2个实现类声明了3个具体的异常。此时你的客户端程序可以很好的处理这些异常,当时如果那天有了一个新的实现类并且他声明了一个新的异常,你的客户端就不知道应该如果处理了。

不过貌似对于一个通用的接口,一般比较难对所有的实现进行预期,也就无法在接口定义的时候就声明所有的异常,那么是声明一个比较抽象的异常还是使用非受检异常呢,那就仁者见仁了。
  
18 楼 czpsailer 2009-11-12  
<p>    查看了一些关于Exception的讨论,发现对于如何何时处理异常和使用Checked Exceptions还是Unchecked Exceptions是讨论很激烈的话题呀!如何很好的处理和使用异常,的确是一件不容易的事情?好多时候容易使人感到疑惑!<br><br>  <strong>  对于“疑惑1:在设计接口的时,对于接口方法何时需要声明抛出受检异常或者说所有的接口方法最后都声明抛出受检异常?” 我比较同意前面joachimz的观点。</strong></p>
<div class="quote_title">
<div class="quote_title"> <strong>joachimz</strong>写道</div>
</div>
<div class="quote_title">
<div class="quote_div">接口就是约定,异常是返回结果之一。<br><br>对于系统性异常,例如网络可能中断,未知的程序错误等等,这种处理成运行时异常,不作申明比较好,反正接收的人也没办法做任何处理<br><br>对于有业务性的错误,例如取款时,余额不够、权限不够、超出最大取款限制等等,这类错误,最好,每个场景,定义一个异常,在申明中逐一说明,总之,异常是帮助使用者了解、处理不同的错误场景。使用者可以根据错误类型的不同,给用户提供不同的处理方式和流程。当然,如果你提供给用户的只是提示信息,就没必要再区分类型了<br><br>异常处理方式上,还有一个办法是对异常编码,那就只需要一种类型了,类似SqlException。两种方式都可行,重点是要让约定更加明确、翔实</div>
</div>
<p><br>      接口可以为声明业务性的错误,也就是对于UseCase中的每个异常流声明一个Checked Exception。这个异常最好是抽象的(例如,一个从文件、数据库或者 JNDI 装载资源的方法在不能找到资源时,应该抛出某种 ResourceNotFound 异常,而不是更底层的 IOException 、 SQLException 或者 NamingException ,就像Bloch 在《Effective Java》中提出的第 43 条的提到的:“方法在遇到失败时应该抛出一个异常,但是该异常应该反映该方法做什么,而不是它如何做。”).<br><br>   public interface IBusiness{  <br><br>         public void method() throws BusinessException1,BusinessException2,。。。;<br><br>   }<br><br>      要做到以上的情况,必须要对业务进行透彻的分析,清楚的知道正常的业务流程和会出现那些错误的业务流程(从业务上说的错误),这样才能设计出完善的接口来。否则,如果接口定义不完善,以后发现还有错误流程没考虑进去那以后改起接口来将是一个灾难呀。<br><br>      我个人的想法:是否能将业务尽量的细粒度化,使得容易明确业务的所有错误和正常的流程,来避免接口重构(还请各位大大指教)?<br><br>    <strong> 在一些项目和开源的项目看到过的一种解决方式:在接口声明中使用一个抽象的业务异常类,在具体接口实现中抛出这个抽象类的子类。</strong><br>     <br>    public interface IBusiness{<br><br>          public void method() throws AbstractBusinessException;<br><br>    }<br><br>    public class BusinessImplA implements IBusiness{<br><br>         public void method() throws SpecificBusinessException1 {<br>               //业务操作<br>         }<br>   <br>    }<br><br>    public class BusinessImplB implements IBusiness{<br><br>         public void method() throws SpecificBusinessException2 {<br>               //业务操作<br>         }<br>   <br>     }</p>
<p>     注:AbstractBusinessException继承自Exception,SpecificBusinessException1,SpecificBusinessException2 继承AbstractBusinessException。</p>
<p> </p>
<p>     <strong>使用方式一:</strong></p>
<p> </p>
<p>         每个具体的业务异常类(如SpecificBusinessException1这样的)本身表示具体的一个业务错误,而接口声明的AbstractBusinessException只是为了能在子类中抛出具体的业务异常。带来的好处之一是当以后发现需要添加新的业务错误(添加新的业务异常)时候,无需修改客户端代码。</p>
<p> </p>
<p>         我觉得这种使用方式是不合理的,这样其实把一个接口方法的责任约定方式到了不同的地方(实现类的方式签名中)。接口的实现是无法预期的,客户端难以在出现异常时候确定具体是那个错误(除非客户端程序员能够获取到并且阅读所有的实现类(包括现在实现和将来实现)的API,但这是不可能的)并且进行相应的处理,此时的异常仅仅是对业务执行的错误的指示,无法成为进行恢复或近一步操作的指示。这种方式不值得提倡,因为我们应该在前期就透却全面的分析业务,避免出现遗漏业务流程的情况存在;而对于业务的变更,则应该选择重构。</p>
<p> </p>
<p>     <strong>使用方式二:</strong></p>
<p> </p>
<p>         对异常编码,子类只是简单的包含不同的错误码,定义一个统一的异常字典。客户端获取异常后获取到错误码根据其进行相应处理。</p>
<p> </p>
<p>         以下为耶鲁CAS的中的代码摘要:</p>
<p> </p>
<p>         public abstract class AuthenticationException extends Exception {<br><br>             private String code;<br><br>             public AuthenticationException(final String code) {<br>                   this.code = code;<br>             }<br>             .....<br>         }<br><br>       public class BadCredentialsAuthenticationException extends AuthenticationException {<br><br>            public static final BadCredentialsAuthenticationException ERROR = new BadCredentialsAuthenticationException();<br><br>            private static final String CODE = "error.authentication.credentials.bad";<br><br>             public BadCredentialsAuthenticationException() {<br>                   super(CODE);<br>             }<br>             .....<br>       }</p>
<p> </p>
<p>       我觉得这种使用方式就比较合理了,不过这种合理性同样是建立在前期对业务的透却全面的分析基础上。<br><strong></strong></p>
<p> </p>
<p>       <br>     <br>     <br></p>
<p> </p>
17 楼 pipilu 2009-11-12  
joachimz 写道
pipilu 写道
czpsailer 写道
在接口有多个不同的实现类时,不同的实现又可能抛出不同的异常,这样就无法在接口声明中将这些具体异常全部声明出来了,这时候使用一个抽象的异常就比较可行了。可是如果这样的话,我觉的使用接口的地方,就无法明确到底会出现哪些具体的异常了。这样貌似异常的使用原则(尽量指定具体的异常)有些相违背了。


这个接口本身都不知道会抛出什么异常,为什么还要向上抛出呢?(除非是上层调用可以处理的异常),自己都不确定的,上一层更没法知道怎么处理你这些异常了。不如就在本层处理,或者转成运行时异常。

这个是在稳定性与灵活性上去权衡:有一个基础类,可以保持接口稳定,让不同使用场景自行去约定异常。只有通用接口才有这样的需求,一般是框架类。具体子类实现的时候,还需要与使用者自行去约定异常。

一般业务逻辑中,专用接口,则需要详细定义异常。


有道理。
这种情况下,我倾向于交由实现类来自行决定抛出运行时异常,使用接口的开发人员通过阅读文档来了解实现类可能会抛出的异常。避免异常声明给调用者带来负担。
16 楼 20029388 2009-11-12  
具体问题具体分析了,业务规定啥样的异常就要抛啥异常,接口只是一个规则, 看具体的规则,如果你的接口比较通用那么抛出的异常也要通用,就是异常尽量要大一点就是exception 然后实现类抛的异常更具体一点,如nullpointexception等等
15 楼 Aguo 2009-11-12  
统一异常类型,比如自定义一个 ServiceException
14 楼 joachimz 2009-11-12  
pipilu 写道
czpsailer 写道
在接口有多个不同的实现类时,不同的实现又可能抛出不同的异常,这样就无法在接口声明中将这些具体异常全部声明出来了,这时候使用一个抽象的异常就比较可行了。可是如果这样的话,我觉的使用接口的地方,就无法明确到底会出现哪些具体的异常了。这样貌似异常的使用原则(尽量指定具体的异常)有些相违背了。


这个接口本身都不知道会抛出什么异常,为什么还要向上抛出呢?(除非是上层调用可以处理的异常),自己都不确定的,上一层更没法知道怎么处理你这些异常了。不如就在本层处理,或者转成运行时异常。

这个是在稳定性与灵活性上去权衡:有一个基础类,可以保持接口稳定,让不同使用场景自行去约定异常。只有通用接口才有这样的需求,一般是框架类。具体子类实现的时候,还需要与使用者自行去约定异常。

一般业务逻辑中,专用接口,则需要详细定义异常。
13 楼 joachimz 2009-11-12  
Dreamer 写道
看了各位高手的回复后有点自己的看法:不赞成为业务需要而设计自定义异常类的做法(如余额不足、没有权限等),因为异常处理的开销比较大。鄙人认为业务上的问题还是通过普通的逻辑判断进行处理比较妥当。

与IO、数据库访问相比,1ms的消耗应该不在考虑范围内。

是否需要定义异常,与你的设计、职责划分很有关系:还是以取款为例,如果你要求别人在调用之前,必须先检查好金额、权限等所有异常,你可以不考虑异常。

但从程序的Robust、从简化使用的角度,一般还是要去考虑的,不能把所有的前置条件、后置条件都交给调用方
12 楼 Dreamer 2009-11-12  
看了各位高手的回复后有点自己的看法:不赞成为业务需要而设计自定义异常类的做法(如余额不足、没有权限等),因为异常处理的开销比较大。鄙人认为业务上的问题还是通过普通的逻辑判断进行处理比较妥当。
11 楼 pipilu 2009-11-12  
czpsailer 写道
在接口有多个不同的实现类时,不同的实现又可能抛出不同的异常,这样就无法在接口声明中将这些具体异常全部声明出来了,这时候使用一个抽象的异常就比较可行了。可是如果这样的话,我觉的使用接口的地方,就无法明确到底会出现哪些具体的异常了。这样貌似异常的使用原则(尽量指定具体的异常)有些相违背了。


这个接口本身都不知道会抛出什么异常,为什么还要向上抛出呢?(除非是上层调用可以处理的异常),自己都不确定的,上一层更没法知道怎么处理你这些异常了。不如就在本层处理,或者转成运行时异常。
10 楼 iaimstar 2009-11-12  
抛出抽象异常

比如 baseAbstractException-
下有两个异常 一个sysE一个bussE
然后所有异常从这两个异常扩展
9 楼 shelocks 2009-11-12  
    接口就是功能的抽象和约束,我感觉,一般不需要在这样的一个抽象层面上抛出异常,因为你必须考虑一下抛出的异常是所有实现都必须的共性吗?如果你在接口的设计中抛出异常,那么相当于给各种实现套上了一层“枷锁”,而这些受检异常本来可以在更具体的层次上处理的。
    至于抛出的是自定义的异常还是已定义的异常(如 exception),这完全看需要,如果你觉得已定义的异常可以很好的描述该异常,使用已定义异常就可以了;如果你想对异常提供进一步的描述,以便更符合当前的应用,那你可以选择自定义异常。
8 楼 Bernard 2009-11-12  
碰到这个问题正是在抛出异常不明确的情况下产生的。
在接口中不声明异常意味着在实现中阻断处理异常。
声明一个独立异常意味着实现无法阻断异常。
而是否在实现中阻断异常是无法猜测的。
thorws Exception是比较折中的做法,不过在使用时还得在外部拦截。
如果实现类外部用户不可控,建议不声明异常。
如果实现类外部提供了可拦截接口,建议throws Exception。
如果实现类内部有明确的异常层次建议设计一个可供继承的异常。
7 楼 Rooock 2009-11-12  
抛出异常, 还是捕获异常, 应该对结合当前的任务来看.
如果当前任务能够正确处理异常, 就应该捕获;
否则, 就继续往上抛出.

相关推荐

    Java语言程序设计基础篇(Y.Daniel Liang 著)课后编程答案(全)

    Java语言程序设计基础篇是Y.Daniel Liang教授的一本经典教材,主要针对初学者,旨在教授Java编程的基础知识。本书涵盖了从语法基础到面向对象编程的重要概念,为读者提供了全面的学习路径。课后编程答案集是学习过程...

    java常见疑惑与陷阱

    ### Java常见疑惑与陷阱 #### 一、Java基础的常见陷阱 **1.1 不一样的数字的宽类型和窄类型** 在Java中,当我们处理不同的数值类型时,可能会遇到一些意料之外的行为。例如,当一个`byte`类型的数据与一个`int`...

    (官方)Java语言程序设计(原书第8版)基础篇和进阶篇复习题和编程题答案

    【Java语言程序设计复习题与编程题答案解析】 在学习Java这门强大的面向对象编程语言时,官方的《Java语言程序设计》第8版提供了深入的基础篇和进阶篇,帮助读者逐步掌握其核心概念和技术。这本书的复习题和编程题...

    Java语言程序设计进阶篇答案与代码

    这份"Java语言程序设计进阶篇答案与代码"资源将帮助你巩固以上知识点,通过实际代码示例加深理解,解决练习题疑惑,提升编程能力。学习过程中,你可以对照代码理解讲解,结合实际运行结果,加深对Java语言特性的掌握...

    Java语言程序设计基础篇课后答案

    课后答案对于初学者来说是极其宝贵的资源,可以帮助他们验证自己的理解,解决学习过程中的疑惑,从而更好地掌握Java编程的核心知识。 1. **Java语言简介**:Java是一种面向对象的、跨平台的编程语言,由Sun ...

    java语言程序设计基础篇课后答案

    Java语言程序设计基础篇的课后答案涵盖了编程学习的关键领域,包括语法、数据类型、控制结构、类与对象、异常处理、输入/输出(I/O)等。这些答案为初学者提供了深入理解Java编程概念的机会。 1. **Java语法**:Java...

    java项目设计与开发范例源码

    1. **Java基础知识**:源码中的项目通常会涉及到Java的基础语法,如变量、数据类型、运算符、控制结构(if语句、for循环、while循环)、类和对象、继承、多态、接口等。初学者可以借此了解和巩固这些基本概念。 2. ...

    Java程序设计PPT教程JAVA程序设计试卷及题库JAVA学习资料合集

    《Java程序设计》题目样例.docx提供了多种编程题目,这些题目通常会涵盖面向对象编程、异常处理、数据结构、IO流等方面,帮助学习者锻炼实际编程能力。同时,2012-2013《Java程序设计》试卷B卷.docx和试卷A卷则代表...

    java语言程序设计的答案

    这份"java语言程序设计的答案"涵盖了课程中的关键知识点,帮助学生解决课后练习中的疑惑。 在Java语言的学习过程中,理解和掌握基本语法是首要任务。这包括数据类型(如整型、浮点型、字符型和布尔型)、变量的声明...

    解决java中的疑惑

    在Java编程语言中,有很多细节和特性可能会...通过深入学习和实践,初学者可以逐渐克服这些疑惑,成为一名熟练的Java开发者。"JAVA解惑.pdf"这份文档很可能详细阐述了这些问题,建议仔细阅读,以便更好地理解Java编程。

    Java语言程序设计基础篇源代码

    4. **异常处理**:Java提供了异常处理机制,使得程序在遇到错误时可以优雅地处理。源代码中会展示try-catch-finally块的使用。 5. **集合框架**:Java集合框架是一系列接口和类的集合,用于存储和操作对象。如...

    java程序设计基础+进阶答案单双都有

    Java程序设计基础与进阶是学习Java编程的重要环节,涵盖了从基本语法到复杂概念的全面内容。本资源包含了基础篇和进阶篇的课后答案,对于初学者来说,是检验学习成果、解决疑惑的好帮手。不论是奇数题还是偶数题,...

    Java解惑 中文版

    本书深入浅出地探讨了Java语言的核心概念、常见疑惑以及最佳实践,旨在使开发者能够编写出更稳定、更高效的代码。 Java解惑部分涵盖了诸多主题,包括但不限于: 1. **内存管理**:Java的垃圾回收机制是其一大特色...

    最新版的Java-解惑

    《Java解惑》是一本专为Java初学者和进阶者设计的指南,旨在帮助读者解决在学习和实践中遇到的各种问题。这本书深入浅出地解析了Java编程中的常见困惑,涵盖了语言基础、类库应用、多线程、网络编程、异常处理、内存...

    java编程思想练习答案 the think in Java Annotated Solution Guide

    《Java编程思想》是 Bruce Eckel 的经典之作,它深入浅出地介绍了Java这门强大的编程语言。...通过对照书本和答案,你可以独立完成练习,也可以查找疑惑,这对于学习和进阶Java编程都是非常有价值的资源。

    Thing in Java\Thinking in Java 3rd Edition英文版,书后答案及代码

    5. **异常处理**:Java使用try-catch-finally语句块来捕获和处理异常,提供了良好的错误报告机制。 6. **输入/输出流**:Java的I/O系统基于流的概念,包括文件操作、网络通信等。 7. **多线程**:Java内置对多线程...

    java解惑java解惑java解惑

    在Java的世界里,疑惑可能涵盖语法、类库、框架、并发、内存管理等多个方面。下面,我们将深入探讨一些常见的Java解惑知识点。 1. **Java基础** - **变量与数据类型**:Java支持基本数据类型(如int、double等)和...

    21天学通java(英文版).pdf格式

    在本书中,读者将逐步学习Java的基本语法、数据类型、控制结构、类与对象、接口、包、异常处理、输入输出流、集合框架、多线程、网络编程以及数据库连接等内容。此外,书中可能还包含了一些实际项目案例,以帮助读者...

    Java编程思想 Thinking in Java 课后习题答案

    2. **异常处理**:Java中的异常处理是程序健壮性的重要组成部分,习题可能会涉及try-catch-finally语句块,以及自定义异常的创建和抛出。 3. **集合框架**:Java集合框架是数据存储和管理的关键,包括ArrayList、...

    Java解惑(中文).pdf

    《Java解惑(中文)》是一本专门为Java开发者编写的指南书籍,旨在解决在实际编程过程中遇到的各种疑惑和难题。本书以中文语言呈现,使得国内的Java程序员能够更轻松地理解并应用其中的知识。通过阅读这本书,读者...

Global site tag (gtag.js) - Google Analytics