假设你有一个方法可以检查参数(Answer)是否正确,并检查问题是否已经在列表中的答案中也是正确的:
public void addAnswer(Answer answer) {
if (answer.isCorrect()) {
...
}
}
但是,我只想在列表中找到一个答案。我有多种选择。我可以抛出异常,我可以忽略它,我可以从addAnswer返回一些布尔值,告诉我操作是否正常。在这种情况下你应该怎么想?
答案 0 :(得分:8)
规则非常简单:在例外,错误,不可预测的失败中使用例外。当期望事情发生或事情经常发生时,不要使用例外。
在你的情况下,答案不正确并不是错误或真正罕见的事情。这是您业务逻辑的一部分。你可以抛出异常,但只是作为某些验证(断言)的一部分,如果你希望给定点的答案始终是正确的,而且突然之间不是(前提条件失败)。
当然,如果在检查正确性(数据库连接丢失,错误的数组索引)异常时发生某些故障,则需要。
答案 1 :(得分:5)
这完全取决于您想要实现的目标。你的方法的调用者是否已经确定它没有添加两个正确的答案?如果发生这种情况,它是编程错误的标志吗?然后抛出异常,但肯定是未经检查的异常。
如果你的方法的目的是减轻调用者强制执行一个真实答案不变量(虽然我怀疑),那么你可以安排通过boolean
返回值发出信号,调用者的可选信息通道。
如果无法提前知道是否还有其他正确的答案 - 例如,答案是从多个线程甚至进程(通过数据库)同时添加的 - 那么它将是有意义地抛出已检查的异常。
结论:没有一种通用的最佳做法,但对于您想要完成的每个方案都有最佳实践。
答案 2 :(得分:2)
例外警察会像大量的砖块一样落在你身上,我和这个答案一样,用“不要使用流量控制例外”和“不要在正常条件下使用例外”这样的陈述。
第一个语句的问题是异常是一种流控制形式。这使得论证自相矛盾,因而无效。
第二个陈述的问题在于它似乎不可避免地伴随着无休止地重新定义异常条件。你会在这个网站上找到一些例子:例如,一个生动的讨论,警察坚持认为EOF是“正常的”,因此不应该抓住EOFException,尽管有许多Java API没有给你任何东西在这个问题上的选择。沿着这条路走得足够远,你可以得到任何特殊的东西,因此根本没有机会使用它们。
这些不是逻辑论证。这些是未经审查的教条。
早在大约1989年首次制定时,原始和真实的一点是你不应该向自己抛出异常,用同样的方法处理:换句话说,< em>不要把它当作GOTO。这个原则继续有效。
关于已检查异常的要点是,您强制调用方执行有关处理它们的操作。如果您根据自己的分析认为这是您想要的,请使用例外。或者,如果您使用的API会强制您捕获它们,请在适当的级别捕获它们(无论是什么:留给读者练习)。
换句话说,就像现实世界中的大多数事情一样,这取决于你的自由裁量权和判断力。该功能可以像其他任何东西一样被使用或滥用。
@Exception警察:你会在电话簿中找到我。但要为争论做好准备。答案 3 :(得分:1)
从方法抛出的异常强制调用者在预期某些输入发生异常时采取某些操作。返回值不会强制执行相同的操作,因此调用者可以捕获它并执行某些操作。
如果您希望调用者处理场景以采取一些纠正措施,那么您应该抛出一个已检查的异常(子类java.lang.Exception
)。
答案 4 :(得分:0)
这里的问题是您的API容易出错。我会改用以下方案:
public class Question {
private List<Answer> answers;
private int mCorrect;
// you may want a List implementation without duplicates
public void setAnswers(List<Answer> answers, int correct) {
this.answers = answers;
// check if int is between bounds
mCorrect = correct;
}
public boolean isCorrect(Answer answer) {
return answers.indexOf(answer) == mCorrect;
}
}
因为Answer
本身只是一个声明,并且通常不能true
false
而不与Question
相关联。这个API使得无法获得零个或多个正确答案,并强制用户在添加答案时提供正确答案,因此您的程序始终处于一致状态并且不会失败。
在决定如何发出错误信号之前,最好设计一下API,以便尽可能减少错误。对于您当前的实现,您必须在您身边进行检查,并且客户端程序员也必须检查他的身边。建议的设计不需要检查,双方都会有正确,简洁和流畅的代码。
关于何时使用boolean
以及何时使用Exception
,我经常看到布尔用于镜像底层API(主要是低级C代码)。
答案 5 :(得分:0)
我同意Tomasz Nurkiewicz的回应。我不能评论它,因为我是一个新用户。我还建议,如果addAnswer()方法并不总是要添加答案(因为它们已经存在正确的答案),请将其命名为建议此行为。 “添加”表示正常的集合行为。
public boolean submitAnswer(Answer answer); // returns true is answer accepted
您的确切解决方案可能取决于我们不了解的有关您的应用程序的更大图片。也许你确实想要抛出异常,但也要让调用者负责检查添加答案是否有效。
这是一个丰富的挂毯。
答案 6 :(得分:0)
我会以这种方式实现它:
public class Question {
private int questionId;
private final Set<Answer> options = new HashSet<Answer>();
private final Set<Answer> correctAnswers = new HashSet<Answer>();
public boolean addAnswer(Answer answer) throws WrongAnswerForThisQuestionException {
if(!answer.isValid(questionId)) {
throw new WrongAnswerForThisQuestionException(answer, this);
}
if (answer.isCorrect(questionId)) {
correctAnswers.add(answer);
}
return options.add(answer);
}
}