Как вытащить из файла со строками числа и заполнить ими динамический массив?
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 шт):
В представленном коде есть следующие проблемы:
- "Предсказанная" ошибка компиляции из-за попытки использовать локальную переменную
lines
вне первого циклаwhile
, в котором она объявлена.
Для устранения этой ошибки можно было бы объявить эту переменную до цикла, проинициализировав её, но это не решает основную проблему с логикой кода. - "Странная" логика в первом цикле
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. Код под комментарием // ниже можно не смотреть
также не логичен:
- выбрасывается проверяемое исключение, чтобы сразу же его перехватить и "пожаловаться" на целый файл
- Сканер не сможет прочитать что-то в строку
line2
, так как к этому моменту будут прочитаны все строки из исходного файла.