在 Java 中使用 Try-Catch 防止错误与忽略错误
Preventing vs Ignoring Errors with a Try-Catch in Java
我最近一直在做一些项目,这些项目在二维数组上使用洪水填充来为游戏创建网格地图。
我正在使用的部分洪水填充算法会抓取网格中的相邻 "cells",如果它们是开放的 space 则将其淹没,如果不是则忽略它们。
但是,因为我正在抓取相邻单元格,所以我从数组中抓取相对于当前单元格的项目,如下所示:grid[y][x-1]
。
显然,当 x == 0
时会抛出越界错误。为了解决这个问题,我一直在使用条件语句来检查我正在访问的索引是否在数组中。像这样:
if(x - 1 >= 0){do what I need to that neighbor}
我知道我也可以通过使用 try catch 来解决错误。
但是,我不确定哪个是正确的解决方案。
我有几个具体问题:
1) 使用条件方法来防止错误发生,是否需要更多的开销并降低效率? (我可能被淹没了数千个单元格)
2) catch 块究竟是如何工作的?它是否有条件地在后台检查错误?
我还制作了一个非常小的演示代码来向您展示我在说什么,只是按比例缩小了:
public static void main(String[] args) {
//declare our test array and initialize size 3
String [] testArray = new String[3];
//This is here for one of the methods I have been trying to avoid errors on
int indexAdjuster = 5;
//this the index of the array we are adjusting
int i = 0;
//now throw an error! uncomment to confirm there is an error if you want
//testArray[i-indexAdjuster] = "error";
//testArray[i+indexAdjuster] = "error";
//IGNORE the error with a try catch
try{
//this would result in an out of bounds exception below index 0 (-5 specifically)
testArray[0-indexAdjuster] = "error";
//this would result in an out of bounds exception above index 2 (5 specifically)
testArray[0+indexAdjuster] = "error";
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("There was an error, but I ignored it");
}
//PREVENT an error with a condition test
//it first checks if the adjusted index is at least 0
//then it checks if the adjusted index is less than the length of the array
if(i - indexAdjuster >= 0 && i + indexAdjuster < testArray.length){
//this would result in an out of bounds exception below index 0 (-5 specifically)
testArray[0 - indexAdjuster] = "This would be an error, but it is prevented";
//this would result in an out of bounds exception above index 2 (5 specifically)
testArray[0 + indexAdjuster] = "This would be an error, but it is prevented";
}else{
System.out.println("We just prevented the error");
}
System.out.println("Test Complete");
}
使用 if 语句检查边界会在每次循环迭代中产生大量开销。
我建议你分配一个更大的数组 1,比如:
String [] testArray = new String[3+1];
这导致您不需要任何 if 条件。
在回答您有关异常处理的问题时,它不会 运行 任何后台条件。它 运行 是您的代码,在导致访问冲突后确定您捕获了子句。
这具体取决于您主要关注的是什么:速度还是干净的代码。
如果错误情况很少发生并且检查成本很高,则捕获异常可能比事先检查成本更低。这与不应该将 catch 块用于常规流量控制的普遍接受的规则相冲突。应该使用异常来捕获 unexpected 错误情况,数组外的索引几乎不会意外。
测试也可以提取到单独的方法中,使代码更易于阅读:
static boolean isValidIndex(String[] array, int i) {
return i >= 0 && i < array.length;
}
或使用弹性访问方法:
static String getIndex(String[] array, int i) {
return i >= 0 && i < array.length ? array[i] : null;
}
(您可能希望将 null 替换为表示无效值的常量值)。
在您的代码中,您可以简单地对您计算的任何索引使用 getIndex() 方法,并作用于 值 它 returns 而不是索引。分配给索引也可以这样做,如果它适合于忽略对不存在的索引的尝试分配:
static void setIndex(String[] array, int i, String value) {
if (i >= 0 && i < array.length)
array[i] = value;
}
您面临的主要问题是确定越界条件是否只是具有合理默认处理选项的正常情况,或者它是否代表真正的错误,需要 中止 方法或程序。
如果它是真正的错误条件,请不要阻止它,也不要捕获它。让它抛出并冒泡调用堆栈。无论调用者级别是什么,整个操作都应该是响应异常的级别。明智地决定谁负责处理很重要,深入的细节方法通常没有足够的信息来做出合理的决定错误的含义 - 在这些情况下将责任分配给调用者(重复直到调用者 可以做决定)。
我最近一直在做一些项目,这些项目在二维数组上使用洪水填充来为游戏创建网格地图。
我正在使用的部分洪水填充算法会抓取网格中的相邻 "cells",如果它们是开放的 space 则将其淹没,如果不是则忽略它们。
但是,因为我正在抓取相邻单元格,所以我从数组中抓取相对于当前单元格的项目,如下所示:grid[y][x-1]
。
显然,当 x == 0
时会抛出越界错误。为了解决这个问题,我一直在使用条件语句来检查我正在访问的索引是否在数组中。像这样:
if(x - 1 >= 0){do what I need to that neighbor}
我知道我也可以通过使用 try catch 来解决错误。
但是,我不确定哪个是正确的解决方案。
我有几个具体问题:
1) 使用条件方法来防止错误发生,是否需要更多的开销并降低效率? (我可能被淹没了数千个单元格)
2) catch 块究竟是如何工作的?它是否有条件地在后台检查错误?
我还制作了一个非常小的演示代码来向您展示我在说什么,只是按比例缩小了:
public static void main(String[] args) {
//declare our test array and initialize size 3
String [] testArray = new String[3];
//This is here for one of the methods I have been trying to avoid errors on
int indexAdjuster = 5;
//this the index of the array we are adjusting
int i = 0;
//now throw an error! uncomment to confirm there is an error if you want
//testArray[i-indexAdjuster] = "error";
//testArray[i+indexAdjuster] = "error";
//IGNORE the error with a try catch
try{
//this would result in an out of bounds exception below index 0 (-5 specifically)
testArray[0-indexAdjuster] = "error";
//this would result in an out of bounds exception above index 2 (5 specifically)
testArray[0+indexAdjuster] = "error";
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("There was an error, but I ignored it");
}
//PREVENT an error with a condition test
//it first checks if the adjusted index is at least 0
//then it checks if the adjusted index is less than the length of the array
if(i - indexAdjuster >= 0 && i + indexAdjuster < testArray.length){
//this would result in an out of bounds exception below index 0 (-5 specifically)
testArray[0 - indexAdjuster] = "This would be an error, but it is prevented";
//this would result in an out of bounds exception above index 2 (5 specifically)
testArray[0 + indexAdjuster] = "This would be an error, but it is prevented";
}else{
System.out.println("We just prevented the error");
}
System.out.println("Test Complete");
}
使用 if 语句检查边界会在每次循环迭代中产生大量开销。 我建议你分配一个更大的数组 1,比如:
String [] testArray = new String[3+1];
这导致您不需要任何 if 条件。 在回答您有关异常处理的问题时,它不会 运行 任何后台条件。它 运行 是您的代码,在导致访问冲突后确定您捕获了子句。
这具体取决于您主要关注的是什么:速度还是干净的代码。
如果错误情况很少发生并且检查成本很高,则捕获异常可能比事先检查成本更低。这与不应该将 catch 块用于常规流量控制的普遍接受的规则相冲突。应该使用异常来捕获 unexpected 错误情况,数组外的索引几乎不会意外。
测试也可以提取到单独的方法中,使代码更易于阅读:
static boolean isValidIndex(String[] array, int i) {
return i >= 0 && i < array.length;
}
或使用弹性访问方法:
static String getIndex(String[] array, int i) {
return i >= 0 && i < array.length ? array[i] : null;
}
(您可能希望将 null 替换为表示无效值的常量值)。
在您的代码中,您可以简单地对您计算的任何索引使用 getIndex() 方法,并作用于 值 它 returns 而不是索引。分配给索引也可以这样做,如果它适合于忽略对不存在的索引的尝试分配:
static void setIndex(String[] array, int i, String value) {
if (i >= 0 && i < array.length)
array[i] = value;
}
您面临的主要问题是确定越界条件是否只是具有合理默认处理选项的正常情况,或者它是否代表真正的错误,需要 中止 方法或程序。
如果它是真正的错误条件,请不要阻止它,也不要捕获它。让它抛出并冒泡调用堆栈。无论调用者级别是什么,整个操作都应该是响应异常的级别。明智地决定谁负责处理很重要,深入的细节方法通常没有足够的信息来做出合理的决定错误的含义 - 在这些情况下将责任分配给调用者(重复直到调用者 可以做决定)。