Чтение в остановках после обработки исключения внутри цикла - PullRequest
0 голосов
/ 09 мая 2018

У меня тут довольно странный вопрос. После создания и обработки моего исключения 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 голосов
/ 09 мая 2018

Насколько я понимаю, hotelData объявлено как поле класса (класс global).

При чтении в текстовом файле вы должны учитывать некоторые аномалии, которые могут произойти (или нет).Простые шаги могут быть предприняты, чтобы гарантировать, что чтение этого текстового файла будет относительно успешным.Если ваше приложение создает текстовый файл, то ваш показатель успеха значительно возрастает, так как вы можете контролировать, как он написан, но, если ваше приложение не создает текстовый файл или текстовый файл скомпилирован из удаленных источников, тогда вероятность успеха может быть уменьшена, еслипредпринимаются шаги для обеспечения ожидаемых результатов.

На мой взгляд:

  • Текстовый файл должен быть идентифицируемым, чтобы гарантировать, что соответствующий текстовый файл действительночитается для обработки.Если текстовые данные взяты из файла CSV, то строка CSV Header должна быть самой первой строкой в ​​файле, и следует выполнить чтение этой строки и сравнить ее с тем, чтобы убедиться, что правильный файлдоступ кЭто особенно верно, если файл должен быть выбран любым числом пользователей (возможно, с помощью средства выбора файлов).Если строка Идентификатор файла (или дескриптор) не существует в вашем текстовом файле как первая строка файла, то, возможно, вам следует рассмотреть возможность его использования, даже если он считается Строка комментария , где строка может начинаться с, возможно, точки с запятой (; ) в качестве первого символа строки.Все, что может идентифицировать файл как правильный файл для обработки.
  • Пустые строки и любые строки, которые считаются Строки комментариев , должны игнорироваться.Это включает в себя любые строки файла, известные , а не , чтобы быть действительными Линии данных , какими бы они ни были.В общем случае пара строк кода, состоящая из оператора if и нескольких условий, может решить эту ситуацию.
  • Никогда не рассчитывайте на фактические Линии данных (строки данных, которые вы будете обрабатывать), чтобы хранить все необходимые данные, ожидаемые.Это особенно верно при манипулировании split данными с разделителями с помощью таких методов, как Integer.parseInt () или Float.parseFloat () в качестве простых примеров.На самом деле это самая большая проблема в вашей конкретной ситуации.Обратите внимание на примеры строк данных, которые вы указали в своем сообщении.Первая строка состоит из 10 частей данных с разделителями, вторая строка данных состоит из 8 частей данных с разделителями, а третья строка снова состоит из 10 частей данных с разделителями.Это вторая строка данных , которая является проблемой здесь.Когда эта строка разбита, результатом будет массив ( info [] ), который будет содержать 8 элементов (индекс от 0 до 7), а метод readLine () ожидает всегда имеет дело с массивом, состоящим из 10 элементов (индекс от 0 до 9).Обрабатывая вторую строку данных, угадайте, что произойдет, если будет нажата строка кода int suiteroom = Integer.parseInt(info[8]);.Правильно, вы получаете ArrayIndexOutOfBoundsException , потому что просто нет индекса 8 в массиве info [] .Вы должны обрабатывать подобные ситуации в своем коде и готовиться к ним.Не полагайтесь на обработку исключений, чтобы заботиться о бизнесе для вас.Вся идея состоит в том, чтобы избегать исключений , если это вообще возможно, но есть моменты, когда это необходимо.Я не верю, что это один из них.

Без доступа к вашим классам кода я просто естественно предположу, что возвращаемые вами методы действительны и функционируют, как запланировано.Имея это в виду, вот как я бы отформатировал текстовый файл Hotels:

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

Первая строка файла - это строка File Descriptor . Вторая строка - это Blank Line просто для более удобного просмотра файла. Третья строка считается строкой комментария , потому что в этом случае она начинается с точки с запятой (; ). На самом деле вам решать, что делать, чтобы строка файла рассматривалась как строка комментария. Эта строка просто действует как строка заголовка и описывает, что означает каждый фрагмент данных в любой строке данных . Четвертая строка - это, конечно, еще одна пустая строка, и еще раз, для облегчения просмотра файла. Все оставшиеся строки файла - это Строки данных , и это строки файла, которые вы хотите обработать.

Для чтения файла ваши методы могут выглядеть следующим образом:

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 () переменные метода инициализируются для хранения значений по умолчанию, если не все значения присутствуют в каком-либо заданном файле Строка данных. Блок switch гарантирует, что обрабатываются только предоставленные значения строки данных независимо от способа предоставления данных, остальные значения заполняются по умолчанию. Это исключает возможность возникновения ArrayIndexOutOfBoundsException при работе с массивом info [] .

Где parseFloat () и parseInt () используются для преобразования строки в соответствующий тип данных, сначала проверяется, чтобы убедиться, что это действительное числовое представление данных Тип, к которому мы обращаемся. Для этого используется метод String.matches () в сочетании с регулярным выражением.

Приведенный выше код, конечно, можно оптимизировать гораздо дальше, но я чувствую, что он дает хорошее описание того, что можно сделать, чтобы повысить успешность чтения и обработки файла (ов).

В качестве примечания также понятно, что вызывает вызов одного из ваших собственных методов ( readLine () ) с тем же именем, что и метод, используемый BufferedReader. До вас, но, возможно, это было бы лучше назвать как processReadLine ()

Цены должны быть как минимум в формате с плавающей запятой или в двойном типе данных

...