6

我有以下 API:

public interface MyApi {

   /**
    * Performs some stuff.
    * @throws MyException if condition C1
    */
   public void method() throws MyException;
}

我现在在我的 API 实现中执行以下修改

public class MyApiImpl {

   public void method() throws MyException {
     if (C1) {
       throw new MyException("c1 message");
     }
     ...
   }
}

替换为:

public class MyApiImpl {

   public void method() throws MyException {
     if (C1) {
        throw new MyException("c1 message");
     } else if (c2) {
        throw new MyException("c2 message");
     }
     ...
   }
}

您认为这是 API 损坏吗?

客户端的代码仍将编译,但 API javadoc 定义的方法协定不再受到尊重,因为 MyExcepiton 是由“新”条件引发的。

如果只更新我的 API jar 文件,客户端应用程序仍然可以工作,但取决于客户端捕获异常的方式,应用程序行为可能会发生很大变化。

你对此有何看法?

4

6 回答 6

7

是的,当 C1 不发生时,您通过抛出异常来破坏接口的合同。

根据经验,接口契约越模糊,越容易不破坏:) 如果接口不是根据显式 C1 定义的,而是根据更一般的术语定义的,则提供了更大的灵活性。

于 2009-06-24T13:09:52.093 回答
6

我的观点是,您不应该更改文档中 API 定义的合约。如果您需要新的行为,您应该 a.) 创建一个可由客户端调用以反映此新行为的新方法,或者 b.) 与客户讨论更改的需求并让他们意识到这一点。

这确实可以双向进行,您和您的客户之间的方法将是什么。

于 2009-06-24T13:08:46.933 回答
1

这在很大程度上取决于 c2 是什么。它是否在现有合同的逻辑范围内?如果是这样,您通过抛出 MyException 来满足合同。如果不是,那么您可能需要抛出一种新的异常类型。

我应该指出,我不是检查异常的忠实拥护者。最终,强迫某人处理异常并不一定会使他们的代码更好或更安全(实际上它可能会产生相反的效果,因为他们可以草率地吞下虚假异常)。

于 2009-06-24T13:10:30.987 回答
1

我会说“不”,没有 API 损坏,除非 MyException 是 RuntimeException。然后就是。

无论如何,我会为条件 C2 子类化 MyException

并且条件 C1 和 C2 都应该是“异常”恕我直言,我不会养成抛出异常的习惯

于 2009-06-24T13:13:44.427 回答
1

这是一个破损。API 是由语言结构强制执行还是仅记录在案是无关紧要的。

这种破坏是否会导致客户端代码出现问题是另一个问题。可能是您正在修复一个缺陷,需要以这种方式覆盖案例 C2 来修复它。从这方面来看,客户端代码开发人员可能会很高兴您进行了此更改(假设他们当前没有以面对更改时会中断的方式解决该缺陷!)

于 2009-06-24T13:15:21.507 回答
1

我认为这里的问题是您制作了部分接口,实现特定条件。如果“C1”条件只是您实现的一部分,那么您可以简单地创建一个新实现,在“C1”或“C2”上引发异常而不会破坏接口。

于 2009-06-24T13:15:29.587 回答