Java 我应该如何做到这一点而不抛出异常?

Java 我应该如何做到这一点而不抛出异常?,java,exception-handling,Java,Exception Handling,我对Java相当陌生,我正试图了解异常以及它们应该在什么时候使用。我一直在使用它们作为错误检查的一种形式,但我遇到过一些人说,异常应该只用于程序无法控制的事情,例如用户错误 我有一个函数,对于给定的二维直线,计算xMin和xMax之间的所有y值。如果直线是垂直的,此函数将引发异常,因为不可能计算垂直直线上y的所有值。在两个y值之间也有一个等价的函数查找点,如果直线是水平的,则会抛出一个错误 findPointsInRangeOfX (int xMin, int xMax) throws Line

我对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-and-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?

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

另一个注意事项是:不要对程序流使用异常

您应该将其拆分为以下内容:

bool isVertical(parameters){}
bool isHorizontal(parameters){}
SomeClass CalculateVertical(parameters){}
SomeClass CalculateHorizontal(parameters){}
if(isVertical(something)){
 CalculateVertical(something);
else if (isHorizontal(something)){
 CalculateHorizontal(something);
}
您的程序流可能如下所示:

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
}

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

或者您可以进行如下修改:

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 ..
        }
    }
}

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

专门针对你的问题。拆分功能怎么样。生成两个函数来检测给定行是水平行还是垂直行(例如布尔值isVertical())

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

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

希望这有帮助,
马库斯同意。我会很懒,只会抛出IllegalArgumentException。这是一个已存在的异常,未选中。这将迫使用户在尝试调用方法之前验证输入。因此,我是否应该在CalculateVertical中假设我确实得到了一条垂直线,并且没有任何检查该方法的操作?@Emma:你永远不应该信任用户。我会在
CalculateVertical
中再次调用
isVertical
,并抛出一个异常(如Kayaman所说的
IllegalArgumentException
),如果它返回
false
@Emma,你可以在CalculateVertical方法中再次检查isVertical,但是如果我在CalculateVertical中抛出一个异常,无论如何,我必须在pointsInWindow中使用try catch,这样我就回到了以前的位置,只是在那里额外调用了isVertical。除非我误解了什么?你可能会发现这个堆栈中的一些流在什么时候抛出异常很有趣,就像这个带有其他材料链接的堆栈一样