选中和未选中的例外和设计思路

让我们说这个不可变的记录类型:

public class Record { public Record(int x, int y) { Validator.ValidateX(x); Validator.ValidateY(y); X=x; Y=y; } public final int X; public final int Y; public static class Validator { public void ValidateX(int x) { if(x < 0) { throw new UnCheckedException; } } public void ValidateY(int y) { if(y < 0) { throw new UnCheckedException; } } } } 

请注意,它会抛出一个未经检查的exception。 原因是因为这是一个经常使用的对象,并且必须处理已检查的exception是不方便的。

但是,如果此对象位于类库中,则可以使用它来validation用户输入(或其他一些外部输入)。 现在它开始听起来应该是一个CHECKEDexception,因为输入不再是程序员。

大家都在想? 我应该检查还是取消选中,还是有更好的设计?

更新:

我的混乱来自这个场景:通常记录会像这样使用:

 Record r = new Record(1,2); OtherObj o = new OtherObj(r); 

这取决于程序员,所以未经检查的exception是可以的。

但是,当您从用户获取Record的参数时,您想要对它们进行validation吗? 所以你可以打电话

 Record.ValidateX(inputX); Record.ValidateY(inputY); 

它可能会抛出一个检查exception,因为输入不再受控制?

对不起,我通常不会太在意这个(我个人认为未经检查就好了)。 但这实际上是家庭作业中的一个问题,我想要把它弄好。

更新(2):我开始认为我需要的是ValidateX抛出一个已检查的exception,因为它通常是涉及用户输入时使用的内容。 在这种情况下,我们可以再次要求用户输入。 但是,对于Record构造函数,它将抛出已检查的exception,因为构造具有无效参数的Record是API违规。 新代码如下所示:

 public class Record { public Record(int x, int y) { try { Validator.ValidateX(x); Validator.ValidateY(y); }catch(CheckedException xcpt) { throw new UnCheckedException(xcpt.getMessage()); } X=x; Y=y; } public final int X; public final int Y; public static class Validator { public void ValidateX(int x) throws CheckedException { if(x < 0) { throw new CheckedException; } } public void ValidateY(int y) throws CheckedException { if(y < 0) { throw new CheckedException; } } } } 

现在程序员可以在将参数传递给Record类之前validation它们。 如果没有那么它就是API违规,并且抛出了未经检查的exception。

这听起来怎么样?!

您永远不应该使用未经检查的exceptionvalidation用户输入。 通常会检查exception,因为这样您就不会忘记处理exception。

validationapi中使用的参数是完全不同的类型。 这些应该是未选中的,因为否则你最终会为每个函数调用添加try / catch。 每当一个方法传递一个无效的参数时,这肯定是一个编程错误。 通常的方法是抛出IllegalArgumentException或NullPointerException(或任何其他适合您需要的东西)。 在api调用中留下已检查的删除

  1. 您向api调用者承诺的validation
  2. 预期的exception条件(请求的文件不存在,写入失败等)

除上述内容外,可恢复性对于确定已检查或未检查的exception也很重要。 如果你永远无法恢复(这通常是编程错误中的情况)你可以(或应该?)取得未经检查的exception。

最好不要编写不符合上述指南的代码。 对于您而言,这意味着您必须编写一个函数,在用于validation用户输入时返回布尔值或已检查exception,并在validation函数的输入参数时返回未经检查的exception。 当然,您可以并且应该使用相同的函数来validationexception,只需包装返回布尔或检查exception的函数:

 public boolean validateX(int x) { return x > 0; } private void validateParameter(int x) { if (validateX(x)) { throw new IllegalArgumentException("X is invalid"); } } 

这是一项更多的工作,但它会给你两全其美。 通过将validate参数function设为私有,您可以确保不会在课堂外意外使用它。 当然,您也可以将if(validateX(x)) ...部分放在构造函数中。

请注意,它会抛出一个未经检查的exception。 原因是因为这是一个经常使用的对象,并且必须处理已检查的exception是不方便的。

不,我认为你在这里抛出未经检查的exception的原因是因为它涉及该API用户方违反合同,而不是该方法正常运行期间的exception情况。 请参阅Java SDK对NullPointerException,IllegalArgumentException等的使用,它们是RuntimeExceptions,因为它们代表违反合同。

Bloch,第58项:对可恢复条件使用已检查的exception,对编程错误使用运行时exception。

如果您的类的用户能够通过正确使用API​​(包括不传入记录为无效的值)来避免此问题,那么这是编程错误,因此抛出InvalidArgumentException。

真的,这完全取决于期望。 如果您希望在正常程序流程下输入无效输入,则应该是一个已检查的exception,以便您可以正常恢复。 未经检查的exception是针对程序员无法执行任何操作并且不期望正常发生的错误情况。

如果这真的是针对validation器类,那么我希望它在其允许输入范围内具有exception灵活性,仅仅因为它的存在目的是测试有效性,而不能通过抛出exception来做得很好。

 public interface Validator { public boolean isValid(T object); } public final class PositiveIntegerValidator implements Validator { public boolean isValid(Integer object) { return object != null && object > 0; } } 

根据经验,我总是在组件/ layer / api的公共接口处理exception。 这允许exception冒泡并在顶层处理 – Last Responsible Moment ,同时确保我在代码中处理exception,避免泄漏exception 。

BTW关于这个问题的数据库exception以及关于这个问题的一般exception处理的一些很好的建议