Как вытащить из файла со строками числа и заполнить ими динамический массив?

public static void parseFileToStringList(File file){
    List<String> people = new ArrayList<>();
    List<Integer> numbers = new ArrayList<>();
    try {
        Scanner sc = new Scanner(file);
        String line;
        while (sc.hasNextLine()) {
            line = sc.nextLine().replaceAll("\\D+", "");
            String[] lines = line.split(" ");//проблема возникает здесь
        }
        for (String ln : lines) {
            numbers.add(Integer.parseInt(ln));//и здесь
        }
        // ниже можно не смотреть
        for (int i = 0; i < numbers.size(); i++) {
            if (numbers.get(i) < 0) {
                try {
                    throw new IOException();
                } catch (IOException e) {
                    System.out.println("Некорректный входной файл.");
                }
            } else {
                while (sc.hasNextLine()) {
                    String line2 = sc.nextLine();
                    people.add(line2);
                }
            }
        }
    }
    catch (FileNotFoundException e) {
        System.out.println("Файл не найден.");;
    }

    for (int i = 0; i < people.size(); i++) {
        System.out.println(people.get(i));
    }

Я знаю, что не могу обращаться к массиву lines, так как он инициализирован внутри цикла, но обходить эту проблему созданием второго временного массива и последующим переносом из одного в другой не получается. Из-за того, что цикл for находится в while, первый не может до конца заполнить основной массив временным, пока временный не заполнится до конца, что происходит снаружи цикла for.
И выходит ошибка во втором месте, что не получается парсить "пустые" ячейки массива в динамический.
Как это сделать иначе?


Ответы (1 шт):

Автор решения: Nowhere Man

В представленном коде есть следующие проблемы:

  1. "Предсказанная" ошибка компиляции из-за попытки использовать локальную переменную lines вне первого цикла while, в котором она объявлена.
    Для устранения этой ошибки можно было бы объявить эту переменную до цикла, проинициализировав её, но это не решает основную проблему с логикой кода.
  2. "Странная" логика в первом цикле while при обработке чисел: если все нецифровые символы в прочитанной строке заменить пустой строкой (replaceAll("\\D+", "")), то в результате не останется ни одного пробела или знака минус, то есть в лучшем случае останется одно целое число без знака, в худшем -- пустая строка.
    Следовательно, последующий вызов lines = line.split(" ") подразумевает, что в результате работы первого цикла while останется только массив из одной последней строки.

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

List<Integer> numbers = new ArrayList<>();
try (Scanner sc = new Scanner(file)) {
    while (sc.hasNextLine()) {
        String[] nums = sc.nextLine().replaceAll("[^\\d-]+", " ").split(" ");
        for (String n : nums) {
             if (!n.isEmpty()) {
                 numbers.add(Integer.valueOf(n));
             }
        }
    }
}

Или такой вариант со стримами и без сканера, полезный функционал которого и так не используется в представленном коде:

List<Integer> numbers;
try (Stream<String> lines = Files.lines(file.toPath())) {
    numbers = lines
        .map(line -> line.replaceAll("[^\\d-]+", " ").split()) // Stream<String[]>
        .flatMap(Arrays::stream)   // Stream<String>
        .filter(s -> !s.isEmpty())
        .map(Integer::valueOf)
        .toList();
}

P.S. Код под комментарием // ниже можно не смотреть также не логичен:

  1. выбрасывается проверяемое исключение, чтобы сразу же его перехватить и "пожаловаться" на целый файл
  2. Сканер не сможет прочитать что-то в строку line2, так как к этому моменту будут прочитаны все строки из исходного файла.
→ Ссылка