重构的代码导致ArrayIndexOutOfBoundsException

时间:2016-03-09 07:51:04

标签: java

我正在尝试重构我的代码,但似乎无法弄清楚已发生的变化并导致此异常。

以前,这是有效的。

private Path getPath() throws FileNotFoundException, IOException {
    ...
    String[] actionFirstSplit = line.split(" ");
    if (actionFirstSplit[1].equals("LOAD")) {
        String[] actionSecondSplit = actionFirstSplit[2].split(",");
    ...
    }

它开始变得非常复杂和形式,所以我决定上课。

public class Interpreter {
    int stepLine;
    String stepName;
    String[] actionFirstSplit;
    String[] actionSecondSplit;

    public String[] parseLine(String line) {
        actionFirstSplit = line.split(" ");
        actionSecondSplit = actionFirstSplit[2].split(",");
        for (String s : actionFirstSplit) {
            System.out.println(s);
        }
        for (String s : actionSecondSplit) {
            System.out.println(s);
        }
        return actionSecondSplit;
    }
}

然后我这样称呼它:

private Path getPath() throws FileNotFoundException, IOException {
    ...
    Interpreter action = new Interpreter();
    parametersList = action.parseLine(line);
    ...
    }

在第二种情况下,我明白了:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
    //This line is actionSecondSplit = actionFirstSplit[2].split(",");
    at test.Interpreter.parseLine(Interpreter.java:28)
    at test.Test.getFileOrDirectoryPath(CSU_VM.java:192)
    at test.Test.analyzePath(Test.java:51)
    at test.Test.<init>(Test.java:47)
    at test.Test.main(Test.java:264)

print语句产生了解析结果。

文字输入可能如下所示:

0 LOAD 1,3
1 LOAD 0,2
2 ADD 1,2
3 SUB 0,1
4 DIV 3,1
5 MUL 0,1

2 个答案:

答案 0 :(得分:2)

从你的代码中......

// a list of items, e.g. in a list view
ReadOnlyObjectWrapper<ObservableList<String>> items = new ReadOnlyObjectWrapper<>(
            FXCollections.observableArrayList(new ArrayList<>()));

// a button that is disabled if there are no items
BooleanProperty disabled = new SimpleBooleanProperty();
disabled.bind(Bindings.createBooleanBinding(() -> Boolean.valueOf(items.get().isEmpty()), items));

// a list with results, e.g. from a worker
ReadOnlyObjectWrapper<ObservableList<String>> results = new ReadOnlyObjectWrapper<>(
            FXCollections.observableArrayList(new ArrayList<>()));
// the items are bound to the results (the list is showing partial result then)
items.bind(results);

// the button is still disabled
System.out.println(disabled.get()); // expected true !WORKS!

// add a result (should inform the items and the button)
results.get().add("Hello");

// both list should be identical now
System.out.println(results.get()); // expected [Hello] !WORKS!
System.out.println(items.get()); // expected [Hello] !WORKS!

// the button should not be disabled anymore
System.out.println(disabled.get()); // expected false !FALIED!

// try to re-bind the button
disabled.unbind();
disabled.bind(Bindings.createBooleanBinding(() -> Boolean.valueOf(items.get().isEmpty()), items));
System.out.println(disabled.get()); // expected false !WORKS!

请注意actionFirstSplit = line.split(" "); actionSecondSplit = actionFirstSplit[2].split(","); 正在尝试处理数组的第3个元素。

分割actionFirstSplit[2].split(",");后,它会在line中存储一个数组。但是,如果actionFirstSplit中的元素数量少于3。

actionFirstSplit将为您提供actionFirstSplit[2].split(",");,因为没有第3个元素。

对它进行硬编码是不安全的,并且总是假设ArrayOutOfBoundsException中会有第3个元素。如果您不想更改当前代码,可以执行以下操作:

1)使用条件检查第3个元素是否存在:

actionFirstSplit

2)使用try-catch块封闭您的代码。

actionFirstSplit = line.split(" ");
if(actionFirstSplit.length >= 3){
    actionSecondSplit = actionFirstSplit[2].split(",");
    //do whatever..
}

添加:

您之前的代码是有效的,因为它在进一步拆分之前进行了检查:

actionFirstSplit = line.split(" ");
try{
    actionSecondSplit = actionFirstSplit[2].split(",");
}catch (ArrayIndexOutOfBoundsException){
    //perform actions to handle out of bounds
}

检查它是否为“LOAD”,然后总会有2个元素。

但是在你添加的代码中,在拆分之前没有检查。

答案 1 :(得分:1)

在您的第一个示例中,如果第一个分割的第二个值为“LOAD”,则您将仅调用第二个分割 ,而在第二个示例中,您不执行此类测试。如果它在第二个例子中断了而不是在第一个例子中有相同的字符串,那么我假设你需要做的是添加回检查,所以:

public String[] parseLine(String line) {
    actionFirstSplit = line.split(" ");
    for (String s : actionFirstSplit) {
        System.out.println(s);
    }

    // Ensure that should this condition fail, class state will be consistent
    actionSecondSplit = null;  

    if (actionFirstSplit.length > 2 && actionFirstSplit[1].equals("LOAD")) {
        actionSecondSplit = actionFirstSplit[2].split(",");
        for (String s : actionSecondSplit) {
            System.out.println(s);
        }
    }
    return actionSecondSplit;  // May be unassigned!  Careful!
}

另外,作为一般经验法则,你可能不应该假设第一次拆分也会产生三个值,所以我也加了一个快速检查。如果字符串无效,则actionSecondSplit将为null,并且该方法将返回null。如果这是不可接受的,请考虑抛出IllegalArgumentException