【问题标题】:How should I do this without throwing exceptions?我应该如何在不抛出异常的情况下做到这一点?
【发布时间】:2019-05-06 14:35:33
【问题描述】:

我对 Java 还很陌生,我正在努力了解异常以及何时应该使用它们。我一直将它们用作错误检查的一种形式,但我遇到几个人说异常只能用于程序无法控制的事情,例如用户错误。

我有一个函数,对于给定的二维线,计算 xMin 和 xMax 之间的所有 y 值。如果直线是垂直的,此函数将引发异常,因为不可能计算垂直线上的所有 y 值。还有一个等效的函数可以在两个 y 值之间查找点,如果直线是水平的,则会引发错误。

findPointsInRangeOfX (int xMin, int xMax) throws LineIsVerticalException {
    // check if line is vertical
    // if vertical, throw an exception
    // else calculate the y values for each integer between xMin and xMax
    // return y values
}

我将此函数称为查找给定窗口内一条线上所有点的一部分,由最小和最大 x 和 y 值给出。我不检查此功能中的线是否垂直;相反,我依靠检查 findPointsInRangeOfX 并在方法周围使用 try 和 catch 块。

pointsInWindow (int xMin, int xMax, int yMin, int yMax) {
    try {
        // Find list of all the points between xMin and xMax.
        // Remove from list all points not between yMin and yMax
    }
    catch (LineIsVerticalException e) {
        // If line is vertical, cannot find points between xMin and xMax
        try {
            // Instead, find list of all points between yMin and yMax
            // Remove from list all points not between xMin and xMax
        }
        catch (LineIsHorizontalException e) {
            // This part will never be reached because the line is vertical
            // But the compiler complains if the exception isn't caught
        }
    }
}

这样好吗?我不会因为这样的错误抛出异常 - 有一条垂直线没有任何问题 - 但我用它来告诉 pointsInWindow 它需要找到 y 值而不是 x 值之间的点。我是否应该复制检查以查看 pointsInWindow 函数中的线是否垂直,而不是使用 try catch 块?如果我确实重复了检查,我应该一起摆脱 LineIsVerticalException 吗?

【问题讨论】:

标签: java exception-handling


【解决方案1】:

你必须坚持单一职责原则:每个方法只做一件事。 现在你的方法做两件事:检查它是否是垂直/水平的并计算一些东西。

这里的另一个注意事项:不要在程序流中使用异常。

你应该把它拆分成这样:

bool isVertical(parameters){}
bool isHorizontal(parameters){}
SomeClass CalculateVertical(parameters){}
SomeClass CalculateHorizontal(parameters){}

您的程序流程可能如下所示:

if(isVertical(something)){
 CalculateVertical(something);
else if (isHorizontal(something)){
 CalculateHorizontal(something);
}

示例实现:

SomeClass CalculateVertical(something){
 if(!isVertical(something)) { throw new IllegalArgumentException() }
 // Calculations
}

请注意,程序员不必捕获此异常。

【讨论】:

  • 同意。我会很懒,只是抛出 IllegalArgumentException。这是一个现有的异常,并且未选中。它会强制用户在尝试调用方法之前验证输入。
  • 那么我是否应该在CalculateVertical 中假设我确实得到了一条垂直线,并且没有对该方法进行任何检查?
  • @Emma:你永远不应该信任用户。我会在CalculateVertical 中再次调用isVertical,如果它返回false,则抛出异常(如Kayaman 所说的IllegalArgumentException)。
  • @Emma 你可以在CalculateVertical方法中再次检查isVertical
  • 但是,如果我从CalculateVertical 抛出异常,我将不得不在pointsInWindow 中使用try catch - 所以我回到了与以前相同的位置,只是使用在那里额外调用 isVertical 。除非我误解了什么?
【解决方案2】:

或者你可以像下面这样修改:

pointsInWindow (int xMin, int xMax, int yMin, int yMax) {
    try {
        // Find list of all the points between xMin and xMax.
        // Remove from list all points not between yMin and yMax
    }
    catch (LineIsVerticalException e) {
        // If line is vertical, cannot find points between xMin and xMax
        // do something..
        }
    catch (LineIsHorizontalException e) {
        // unless LineIsVerticalException is superclass of LineIsHorizontalException,
        // this will work 
        // do something ..
        }
    }
}

【讨论】:

    【解决方案3】:

    一般来说,我尝试将异常用于意外问题(例如网络故障),而不仅仅是边界情况。然而,这是一个模糊的区别,取决于您的特定应用程序上下文。

    专门针对您的问题。拆分功能怎么样。创建两个函数来检测给定的行是水平还是垂直(例如 boolean isVertical());。

    在您的 pointsInWindow 函数中,您可以首先检查您是否正在处理垂直/水平线的特殊情况,如果没有进一步调用 findPointsInRange 方法。

    尽量不要重复逻辑,因为这违反了 DRY 原则DRY principle,并且在维护代码时往往会导致进一步的问题。

    希望这会有所帮助, 马库斯

    【讨论】:

      【解决方案4】:
      findPointsInRangeOfX (int xMin, int xMax) throws LineIsVerticalException {
          if(isLineVeritical(xMin, xMax)){
              throw new LineIsVerticalException();
          }
      
          return calculateValuesBetweenMinAndMax(xMin, xMax);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-16
        • 1970-01-01
        • 1970-01-01
        • 2021-09-24
        • 2015-05-01
        • 1970-01-01
        相关资源
        最近更新 更多