0

我目前正在开发一个程序,任何时候我调用 Products[1] 都没有空指针错误,但是当我调用 Products[0] 或 Products[2] 时,我得到一个空指针错误。但是,我仍然得到 2 个不同的输出,几乎就像数组中有 [0] 和 1 或 1 和 2。这是我的代码

    FileReader file = new FileReader(location);
    BufferedReader reader = new BufferedReader(file);

    int numberOfLines = readLines();
    String [] data = new String[numberOfLines];
    Products = new Product[numberOfLines];
    calc = new Calculator();

    int prod_count = 0;
    for(int i = 0; i < numberOfLines; i++)
    {
        data = reader.readLine().split("(?<=\\d)\\s+|\\s+at\\s+");
        if(data[i].contains("input"))
        {
            continue;
        }
        Products[prod_count] = new Product();
        Products[prod_count].setName(data[1]);
        System.out.println(Products[prod_count].getName());
        BigDecimal price = new BigDecimal(data[2]);
        Products[prod_count].setPrice(price);


        for(String dataSt : data)
        {

            if(dataSt.toLowerCase().contains("imported"))
        {
                Products[prod_count].setImported(true);
        }
            else{
                Products[prod_count].setImported(false);
            }

        }



        calc.calculateTax(Products[prod_count]);    
        calc.calculateItemTotal(Products[prod_count]);
        prod_count++;

这是输出:

imported box of chocolates
1.50
11.50
imported bottle of perfume
7.12
54.62

这个印刷作品System.out.println(Products[1].getProductTotal());

这变成了一个空指针System.out.println(Products[2].getProductTotal());

这也变成了一个空指针System.out.println(Products[0].getProductTotal());

4

3 回答 3

3

您正在跳过包含“输入”的行。

if(data[i].contains("input")) {
    continue;          // Products[i] will be null
}

可能最好创建products一个 ArrayList,并只向其中添加有意义的行。

products也应该以小写开头以遵循 Java 约定。类型以大写字母开头,参数和变量以小写字母开头。并非所有 Java 编码约定都是完美的——但是这个非常有用。

代码的其他结构很好,但是数组不是从程序逻辑构建的非常灵活的类型(因为必须预先确定长度,所以跳过需要您跟踪索引,并且它无法跟踪大小为你建立它)。

通常你应该建立列表(ArrayList)。Map(HashMap、LinkedHashMap、TreeMap)和Set(HashSet)也很有用。


第二个错误:正如 Bohemian 所说:data[]您混淆了所有行列表的概念,以及data[]从单行解析/拆分的标记。

“数据”通常是一个没有意义的术语。使用有意义的术语/名称,并且您的程序中出现错误的可能性要小得多。

您可能应该只使用tokens行标记,而不是在需要之前/在外部声明它,也不要尝试按行对其进行索引——因为,很简单,绝对不需要这样做。

for(int i = 0; i < numberOfLines; i++) {
    // we shouldn't need data[] for all lines,  and we weren't using it as such.
    String line = reader.readLine();
    String[] tokens = line.split("(?<=\\d)\\s+|\\s+at\\s+");
    //
    if (tokens[0].equals("input")) {        // unclear which you actually mean.
    /* if (line.contains("input")) { */    
        continue;
    }

当您为问题提供示例输入时,请将其编辑到问题的正文中,以便其可读。将其放在无法正确阅读的评论中,只是在浪费试图帮助您的人的时间。

于 2013-09-22T00:19:32.337 回答
2

错误警报:您正在覆盖data

String [] data = new String[numberOfLines];

然后在循环中:

data = reader.readLine().split("(?<=\\d)\\s+|\\s+at\\s+");

所以谁知道它有多大——取决于拆分的成功与否——但你的代码依赖于它的numberOfLines长度。

于 2013-09-22T00:24:19.853 回答
0

您需要为行号和新产品对象使用不同的索引。如果您有 20 行但其中 5 行是“输入”,那么您只有 15 个新产品对象。

例如:

int prod_count = 0;

for (int i = 0; i < numberOfLines; i++)
{
        data = reader.readLine().split("(?<=\\d)\\s+|\\s+at\\s+");
        if (data[i].contains("input"))
        {
            continue;
        }
        Products[prod_count] = new Product();
        Products[prod_count].setName(data[1]);
        // etc.
        prod_count++; // last thing to do
}
于 2013-09-22T00:30:12.493 回答