46

我正在编写代码来查找和交叉 2 行。当线的斜率相等时,它们不相交。但另一方面,具有相等斜率的输入是完全有效的。

public static Point calculateIntersection(Line line1, Line line2) {

    if (line1 == null || line2 == null) {
        throw new NullPointerException(" some message ");
    }

    if (line1.getConstant() == line2.getConstant()) {
        return new Point(0, line1.getConstant());
    }

    if (line1.getSlope() == line2.getSlope()) {
        throw new IllegalArgumentException("slopes are same, the lines do not intersect.");
    }

    int x = (line2.getConstant() - line1.getConstant()) / (line1.getSlope() - line2.getSlope());
    int y = line1.getSlope() * x + line1.getConstant();

    return new Point(x, y);
}

问题是抛出非法参数异常是正确的做法吗?由于输入是有效的,它并不能完全说服我。

自定义异常是正确的做法吗?听起来是个不错的选择,但额外的意见会有所帮助。

谢谢

4

6 回答 6

50

问题是抛出非法参数异常是正确的做法吗?

这取决于您希望/需要如何“框定”这种情况;即它是错误、用户输入错误还是程序应该能够处理的东西?

  • 如果两条线不相交的情况无疑是一个“错误”,那就没问题了IllegalArgumentException。这就是异常的目的。(请注意,这是一个未经检查的异常,因此期望它不会被捕获/恢复。)

  • 如果这是您希望程序能够自行恢复的情况,那么自定义异常是最好的主意。这样,您就可以减少代码被(例如)库方法抛出(例如)IllegalArgumentException...而不是“两条线相交”以外的含义而混淆的可能性。

  • 如果您希望将这种情况作为输入验证的一部分报告给最终用户,那么通用的“验证错误”异常可能比特定的自定义异常更合适。但是,此方法看起来并非旨在(仅)用于用户输入验证。


在某些情况下,根本不抛出异常可能会更好,但是(IMO)这不是这些情况之一。替代方法是向调用代码返回null或返回一个表示“没有这样的点”的Point值。替代方案的问题是:

  • 如果你退回null应用程序必须处理的null情况......否则会有NPEs。
  • 没有自然Point实例可以用来表示“不是一个点”。

这并不是说您不能使这些替代方案发挥作用。只是在这种情况下,这样做可能会做更多的工作,而且可能不会有明显的回报。

于 2013-06-10T02:10:32.513 回答
4

Line这几乎肯定不应该抛出异常,因为使用任何两个值调用这样的方法是非常有意义的。您已经适当地处理了空值。

您还非常合理地定义了您的类在一种定义不明确的输入情况下的行为,即两条重合的“恒定”(水平)线,您x=0在该线上返回点。对于其他定义不明确的输入,您应该类似地选择返回值:重合垂直线、既不水平也不垂直的重合线以及不重合的平行线。

在我看来,对于最后一种情况——不重合的平行线——最自然的结果是null,反映了没有交点的事实。

然后由客户端决定空交集是否保证异常、错误消息或其他。例如,提示用户输入要相交的线的交互式外壳可能会打印一条错误消息并要求用户再试一次。IllegalArgumentException如果产生平行线的约束相互矛盾,一些更复杂的计算,例如试图为其搜索定义边界的线性优化器,可能想要抛出。

当然,所有这些情况下的返回值(重合线或非重合平行线)都应准确记录在方法的 javadoc 中。

于 2015-05-04T17:09:41.547 回答
2

我会说你做正确的事:你尽早发现病情。要么就是这样,要么人们会抱怨“你的程序有问题,看看这个输入数据,除以 0”。

鉴于在 99+% 的情况下不会出现这样的错误,这是一种异常情况,并且不允许声明已检查的异常,因此未检查的异常看起来确实是正确的选择。

现在,至于是否IllegalArgumentException是“好”,至少是描述这种情况的最接近的例外......你可以,如果你觉得你有一个更好的名字,总是创建你自己的继承RuntimeException

IF另一方面,这种情况并不少见,那么也许应该审查达到该功能的逻辑,以免一开始就遇到这种情况。

于 2013-06-10T02:05:22.107 回答
2

正如@Andy-Lowry 和@KamikazeCZ 所说,这不应该是一个例外。

这个方法不应该关心客户是否期望线总是相交;它应该只为找到两条线的交点而烦恼——这本来就可能不会发生。

如果调用者返回一个表明没有交叉的结果,那么该代码可以决定它是否是无效输入,因为最终用户被适当地警告过,或者他们可以处理的事情(可能通过重新提示),或者抛出一个定制的异常。

那么,回到这个方法应该返回什么?某种标记值,与indexOf集合库中返回 -1 的方式相同。返回null是一个合理的哨兵。在 Java 8 中,您可以返回Optional<Point>, 以帮助提醒调用者可能没有正确的Point.

你还有一个额外的问题:有人要求一条线与它自己的交点是什么?(在数学上,两条线的交点是 0 点、1 点或无限多点。)您可能需要能够返回两个标记值,这在 Java 中涉及更多。这次这种方法可以摆脱这种情况,通过说“在多个答案的情况下,这个方法可能会返回其中任何一个”,或者(我可能会做的)“......返回最接近原点的点” .

顺便说一句,这种想法主要来自单元测试的心态:首先定义正确的答案应该是针对各种极端情况输入,然后再启动代码并让自己承诺某种返回类型等。

最后:比较getSlope()using的结果时==,请注意浮点舍入错误。这可能是在这里做的最好的事情,但它仍然存在问题。但是,您假设(或舍入)与ints 的交点的方式表明,您的问题中可能存在非常特殊的约束/假设。

于 2016-11-26T20:37:20.267 回答
2

请记住,这个问题的更通用版本主要是基于意见的。

如果是我,我会回来null的。在大多数情况下,您不应将异常处理用作流控制的一种形式。null对于使用您的方法的任何代码,返回将有助于避免这种情况。

相关讨论:

不要对流控制使用异常

检索方法是否应该在无法产生返回值时返回“null”或抛出异常?[关闭]

作为控制流的异常是否被视为严重的反模式?如果是这样,为什么?

支持或反对使用 Try/Catch 作为逻辑运算符的论据 [关闭]

于 2019-08-29T15:45:19.303 回答
-1

异常应该用于捕获程序流中的错误(“内部发生了什么”),而不是用于输入验证。我根本不会抛出异常。想一想,这不是“异常”的意思,因为用户输入两条斜率相等的线是完全正常的。

于 2013-06-10T01:58:17.047 回答