在循环内处理异常后读取停止

时间:2018-05-08 22:09:53

标签: java oop indexoutofboundsexception

我在这里有一个非常奇怪的问题。抛出并处理我的ReaderException异常后,我的读入操作仍然在异常的第一次出现时停止。有人可以解释为什么会这样吗?

输入:

Hotel Paradis;Strada Ciocarliei, Cluj-Napoca 400124;46.779862;23.611739;7;200;8;250;1;400
Hotel Sunny Hill;Strada Fagetului 31A, Cluj-Napoca 400497;46.716030;23.573740;4;150;6;190
Golden Tulip Ana Dome;Strada Observatorului 129, Cluj-Napoca 400352;46.751989;23.576580;0;330;0;350;0;600

代码:

public HotelDescriptor readLine(final String line) throws ReaderException {
    System.out.println(line);
    String info[] = line.split(";");
    for (String i:info)
        System.out.println(i);
    String tempname = info[0];
    String tempaddress = info[1];
    float templatitudeh = Float.parseFloat(info[2]);
    float templongitudeh = Float.parseFloat(info[3]);
    int singleroom = Integer.parseInt(info[4]);
    int singleprice = Integer.parseInt(info[5]);
    int doubleroom = Integer.parseInt(info[6]);
    int doubleprice = Integer.parseInt(info[7]);
    int suiteroom = Integer.parseInt(info[8]);
    int suiteprice = Integer.parseInt(info[9]);

    Hotel tempHotel = new Hotel(tempname, tempaddress, templatitudeh, templongitudeh, singleroom, singleprice, doubleroom, doubleprice, suiteroom, suiteprice);
    System.out.println(tempHotel.getName());
    return tempHotel;
    }
public List<HotelDescriptor> readFile(final String hotels) {
    try (BufferedReader buff = new BufferedReader(new FileReader(hotels))) {
        String line = "";
        while ((line = buff.readLine() )!= null) {try {
                hotelData.add(readLine(line));
            } catch (ReaderException e){
                e.printStackTrace();
            } catch (ArrayIndexOutOfBoundsException ex){
                ex.printStackTrace();
            }
            //line = buff.readLine();
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return hotelData;
}

1 个答案:

答案 0 :(得分:0)

我认为 hotelData 被声明为Class字段(类全局)。

在阅读文本文件时,您应该考虑可能发生(或不发生)的一些异常。可以采取简单的步骤以确保读取该文本文件相对成功。如果您的应用程序正在创建文本文件,那么您的成功率会大大提高,因为您可以控制它的编写方式,但是,如果您的应用程序未创建文本文件或文本文件是从远程源编译的,那么成功率可以降低,除非采取措施确保预期的结果。

在我看来:

  • 文本文件应该是可识别的,以确保正确 实际上正在读取文本文件以进行处理。如果文本数据来自 CSV文件然后 CSV标题行应该是第一行 在文件中,应该完成并比较这一行 以便验证是否正在访问正确的文件。这是 特别是如果文件可以被任意数量的选择 用户(可能通过文件选择器)。如果文件标识符 (或描述符)行在您的文本文件中不存在为第一行 那么文件也许你应该考虑使用它,即使它是 被认为是评论专栏,其中的行可能也许就是这样 分号(; )作为该行的第一个字符。什么 可以将文件标识为要处理的正确文件。
  • 空白行和任何被视为注释行的行应该是 忽略。这包括任何已知的实际数据的文件行 线条无论它们是什么。一般来说,有几行代码 由 if 语句和一些条件组成 照顾这种情况。
  • 永远不要指望实际数据线(您将成为数据行 处理)保存预期的所有必需数据。这是 特别适用于使用操作拆分分隔数据 诸如 Integer.parseInt() Float.parseFloat()之类的方法 仅仅是一些例子。这实际上是您特别关注的最大问题 情况。记下您提供的示例数据行 在你的帖子内。第一行由10个分隔的部分组成 数据,第二条数据线由 8 分隔的部分组成 数据,第三行又包含10个分隔符 数据。这是第二条数据线的问题。什么时候 这行被拆分,结果将是一个数组( info [] ) 将包含8个元素(索引0到7),但 readLine()方法是 期望始终处理由10个元素组成的数组 (索引0到9)。在处理第二条数据线时,猜猜是什么 在代码行int suiteroom = Integer.parseInt(info[8]);被命中时发生。没错,你得到了一个 ArrayIndexOutOfBoundsException ,因为 info [] 数组中根本没有索引 8 。您需要在代码中处理这样的情况并准备处理它们。不要依赖 处理业务的异常处理。整个想法 是否避免例外,如果有可能,请注意有时需要。我不相信这是其中之一。

如果不访问您的代码类,我只会自然地假设您的方法返回有效且按计划运行。考虑到这一点,我将如何格式化酒店文本文件:

My App Name - Hotels Data File

;Hotel Name; Hotel Address; Latitude; Longtitude; Single Room; Single Price; Double Room; Double Price; Suite Room; Suite Price

Hotel Paradis;Strada Ciocarliei, Cluj-Napoca 400124;46.779862;23.611739;7;200;8;250;1;400
Hotel Sunny Hill;Strada Fagetului 31A, Cluj-Napoca 400497;46.716030;23.573740;4;150;6;190
Golden Tulip Ana Dome;Strada Observatorului 129, Cluj-Napoca 400352;46.751989;23.576580;0;330;0;350;0;600

该文件的第一行是文件描述符行。第二行是空白行,只是为了更方便地查看文件。第三行被视为注释行,因为在这种情况下,它以分号(; )开头。实际上由您来决定将文件行视为注释行的原因。此行仅用作标题行,并描述了数据行上每个分隔数据的含义。第四行当然是另一个空白行,并且再次,以便于查看文件。其余文件行都是数据行,这些是您要处理的文件行。

要读取文件,您的方法可能如下所示:

public HotelDescriptor readLine(final String line) {
    // Split on various possible combinations of how the
    // delimiter might be formated within a file line.
    String info[] = line.split(" ; |; |;"); 
    // Variables declaration and default initialization values
    String tempname = "";
    String tempaddress = "";
    float templatitudeh = 0.0f;
    float templongitudeh = 0.0f;
    int singleroom = 0;
    int singleprice = 0;
    int doubleroom = 0;
    int doubleprice = 0;
    int suiteroom = 0;
    int suiteprice = 0;

    String strg; // Used to hold the current Array Element in the for/loop
    String regExF = "-?\\d+(\\.\\d+)?"; // RegEx to validate a string float or double value.
    String regExI = "\\d+";             // RegEx to validate a string Integer value.
    for (int i = 0; i < info.length; i++) {
        strg = info[i].trim(); // remove leading/trailing spaces if any
        switch (i) {
            case 0:
                tempname = info[i];
                break;
            case 1:
                tempaddress = info[i];
                break;
            case 2:
                // Is it a float or double numerical value
                if (strg.matches(regExF)) {
                    templatitudeh = Float.parseFloat(info[i]);
                }
                break;
            case 3:
                // Is it a float or double numerical value
                if (strg.matches(regExF)) {
                    templongitudeh = Float.parseFloat(info[i]);
                }
                break;
            case 4:
                // Is it a Integer numerical value
                if (strg.matches(regExI)) {
                    singleroom = Integer.parseInt(info[i]);
                }
                break;
            case 5:
                // Is it a Integer numerical value
                if (strg.matches(regExI)) {
                    singleprice = Integer.parseInt(info[i]);
                }
                break;
            case 6:
                // Is it a Integer numerical value
                if (strg.matches(regExI)) {
                    doubleroom = Integer.parseInt(info[i]);
                }
                break;
            case 7:
                // Is it a Integer numerical value
                if (strg.matches(regExI)) {
                    doubleprice = Integer.parseInt(info[i]);
                }
                break;
            case 8:
                // Is it a Integer numerical value
                if (strg.matches(regExI)) {
                    suiteroom = Integer.parseInt(info[i]);
                }
                break;
            case 9:
                // Is it a Integer numerical value
                if (strg.matches(regExI)) {
                    suiteprice = Integer.parseInt(info[i]);
                }
                break;
        }
    }

    Hotel tempHotel = new Hotel(tempname, tempaddress, templatitudeh, templongitudeh, 
            singleroom, singleprice, doubleroom, doubleprice, suiteroom, suiteprice);
    System.out.println(tempHotel.getName());
    return tempHotel;
}

public List<HotelDescriptor> readFile(final String hotels) {
    try (BufferedReader buff = new BufferedReader(new FileReader(hotels))) {
        String line;
        int lineCounter = 0;
        while ((line = buff.readLine()) != null) {
            // Trim any leading or trailing spaces (spaces, tabs, etc)
            line = line.trim();
            lineCounter++; 
            // Is this the right file to read?
            if (lineCounter == 1) {
                if (!line.equalsIgnoreCase("My App Name - Hotels Data File")) {
                    //No it isn't...
                    JOptionPane.showMessageDialog(this, "Invalid Hotels Data File!",
                            "Invalid Data File", JOptionPane.WARNING_MESSAGE);
                    break; // Get out of while loop
                }
                // Otherwise skip the File Descriptor line.
                else { continue; }
            }
            // Is this a blank or Comment line...
            // Lines that start with ; are comment lines
            if (line.equals("") || line.startsWith(";")) {
                // Yes it is...skip this line.
                continue;
            }
            // Process the data line...
            hotelData.add(readLine(line));
        }
    }
    catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }

    return hotelData;
}

readLine()方法中,变量初始化为保持默认值,不应该在任何给定文件数据行上都存在所有值。 开关块可确保只处理提供的数据行值,而不管数据的提供方式如何,默认值将填写其余数据。这消除了在使用 info [] 数组时发生 ArrayIndexOutOfBoundsException 的可能性。

使用 parseFloat() parseInt()时,首先检查要转换为其各自数据类型的字符串,以确保它是有效的数字表示形式我们要转换的数据类型。 String.matches()方法与正则表达式结合使用。

上面的代码当然可以进一步优化,但我觉得它提供了一个很好的描述,可以做些什么来提高阅读和处理文件的成功率。

作为旁注,通过与BufferedReader使用的方法相同的名称调用您自己的方法( readLine())也是令人困惑的。由您决定,但这可能更好地命名为 processReadLine()

价格至少应为浮点数或双数据类型