Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
针对异常的Java接口的正确设计_Java_Exception_Interface - Fatal编程技术网

针对异常的Java接口的正确设计

针对异常的Java接口的正确设计,java,exception,interface,Java,Exception,Interface,我试图了解如何在Java中正确定义接口,如何在语言(和运行时)中处理异常。 注意:也许这个问题已经被问到并得到了充分的回答,但我在SO(和其他网站)的搜索中没有发现任何直接解决设计问题和我提出的权衡问题的东西。如果能找到一个类似的问题来回答我的问题,我会很高兴地删除这个问题。对于这个冗长的问题,我提前表示歉意,但我想尽可能清楚地说明这个问题。我也知道这一点,但由于我无法改变语言,而且必须在语言中工作,因此我想选择一种在长期内造成最少痛苦的方法 我遇到的反复出现的问题是,当我试图定义自己的接口时,

我试图了解如何在Java中正确定义接口,如何在语言(和运行时)中处理异常。

注意:也许这个问题已经被问到并得到了充分的回答,但我在SO(和其他网站)的搜索中没有发现任何直接解决设计问题和我提出的权衡问题的东西。如果能找到一个类似的问题来回答我的问题,我会很高兴地删除这个问题。对于这个冗长的问题,我提前表示歉意,但我想尽可能清楚地说明这个问题。我也知道这一点,但由于我无法改变语言,而且必须在语言中工作,因此我想选择一种在长期内造成最少痛苦的方法

我遇到的反复出现的问题是,当我试图定义自己的接口时,我面临着如何指定允许接口成员出现哪些异常(如果有)的选择。问题是我无法知道哪些异常是有意义的,因为我无法提前知道我的接口的所有可能实现是什么。为了举例说明,假设我们有以下接口:

// purely hypothetical interface meant to illustrate the example...
public interface SegmentPartition {
    // option 1
    bool hasSegment(Segment s);
    // option 2
    void addSegment(Segment s) throws Exception;
    // option 3
    bool tryAddSegment(Segment s) throws TimeoutException, IOException, ParseException, XmlException, SQLException;
    // option 4
    void optimizeSegments() throws SegmentPartitionException;
}
此接口应预先声明哪些异常类型?我看到的选择是:

  • 不要声明任何异常,实现只能抛出
    RuntimeException
  • 将每个方法声明为引发异常
  • 尝试预测对该接口有意义的每种可能的异常类型,并将它们声明为可丢弃的异常
  • 创建我自己的异常类型(例如,
    SegmentException
    ),并根据需要将其与内部异常一起抛出,以获取更多详细信息
  • 这些方法中的每一种都有问题,而且还不完全清楚所有的权衡可能是什么,我已经针对每种情况提到了一些。理想情况下,我不希望实现抛出任何异常,但这并不总是一个实际的限制。

    对于选项1,问题在于可能引发的许多异常类型不是从RuntimeException派生的(例如IOException或TimeoutException)。当然,我可以将这些特定的异常添加到接口中,然后允许抛出其他运行时异常,但是用户定义的异常呢?这似乎是一个糟糕的选择

    使用选项2我们最终得到的界面似乎可能会导致任何异常(我认为这是真的),并且没有为实现者提供关于实际抛出什么的指导。界面不再是自文档化的。更糟糕的是,此接口的每个调用站点必须声明为抛出异常,或者将对此接口的方法的每个调用包装在
    try{}catch(Exception)
    中,或者创建一个块来捕获异常,并尝试确定它是由接口实现还是该块中的其他内容抛出的。讨厌。或者,使用此接口的代码可以捕获实现可能抛出的特定异常,但这样做违背了创建接口的目的(因为它要求调用方知道实现的运行时类型)。实际上,对于异常(C++、C#、Scala等),这是最接近我所知道的大多数其他语言的选项

    使用选项3时,我必须明确预测可以为我的接口定义的潜在实现,并声明最适合它们的异常。因此,如果我预计我的接口可能通过远程、不可靠的连接实现,我会添加TimeoutException,如果我预计它可能使用外部存储实现,我会包括IOException,等等。我几乎肯定会弄错的。。。这意味着,随着新的实现范例的出现,我将不断地搅动接口(当然,这会破坏所有现有的实现,并要求它们声明抛出非感官异常)。这种方法的另一个问题是会导致难看、重复的代码。。。特别是对于具有许多方法的大型接口(是的,有时需要这些方法),需要在每个实现点重复这些方法

    使用选项4我必须创建自己的异常类型,以及伴随该类型而来的所有负担(可序列化性、嵌套和内部异常、提出合理的层次结构等)。这里似乎不可避免地发生的事情是,每个接口类型都有一个异常类型:InterfaceFoo+InterfaceFooException。除了由此带来的代码膨胀之外,真正的问题是异常类型没有任何意义。。。它只是一种用于将特定接口的所有错误条件捆绑在一起的类型。在某些情况下,您可能可以创建一些异常类型的子类来指示特定的故障模式,但即使这样也值得怀疑

    那么一般来说,在这里做什么才是正确的呢?我意识到可能没有一成不变的规则,但我很好奇有经验的Java开发人员选择做什么


    非常感谢。

    一般来说?根据我的经验,考虑到工程问题的复杂性,以及给定工程环境中可用的选项,具有最大快速价值的答案被给予最高优先级


    优雅是一个意见的问题。然而,在我看来,在add上抛出一个定制的SegmentException(如果有可能的话)似乎是最优雅的,并尝试将异常的可能性降到最低。

    在接口中拥有
    抛出异常(它是一个选中的异常)意味着您知道在什么条件下应该出现这样一个选中的异常
    
     /**
     * ...
     * @return the result returned by one of the tasks
     * @throws InterruptedException if interrupted while waiting
     * @throws TimeoutException if the given timeout elapses before
     *         any task successfully completes
     * @throws ExecutionException if no task successfully completes
     * @throws RejectedExecutionException if tasks cannot be scheduled
     *         for execution
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;