Как реализовать динамическое создание объектов класса?
Есть задача cчитывать из файла построчно имя и возраст, реализовать статический метод, создающий объекты класса Human
и заносящий его в List<Human>
.
У меня реализован отдельный "сбор" возраста и имен, но я не знаю, как реализовать инициализацию новых объектов динамически. Ничего не понял про метод newInstanse()
из той документации, которую нашел.
List<Human> people = new ArrayList<>();
List<Integer> numbers = new ArrayList<>();
List<String> names = 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));
}
}
}
while (sc.hasNextLine()) {
String[] name = sc.nextLine().replaceAll("[^A-Za-zА-Яа-я]", "").split(" ");
for (String nm : name) {
if (!nm.isEmpty()) {
names.add(nm);
}
}
}
if (!isPos(numbers)) {
try {
throw new IOException();
}
catch (IOException e){
System.out.println("Некорректный входной файл");
}
}
else {
for (int i = 0; i < names.size(); i++) {
people.add(new Human(names.get(i), numbers.get(i)));
}
}
}
catch (FileNotFoundException e) {
System.out.println("Файл не найден.");
}
System.out.println(people);
Прошу оставить блоки try/catch
без комментариев, они нужны по условию задачи!
При выводе списка people
получаются пустые скобки [].
Что не так?
Пример списка в файле
Амир 18
Тагир 18
Хамид 18
Усман 26
Нурадил 17
Ответы (1 шт):
Основная проблема представленного кода в том, что он не может заполнить список с именами, так как сканер на первом проходе в цикле while (sc.hasNextLine())
обрабатывает только числовые данные (возраст), и соответственно второй цикл не выполнится.
Если основная задача состоит в том, чтобы вернуть заполненный список Human
, создание и раздельное заполнение двух списков numbers
и names
представляется излишним.
Поскольку каждая непустая строка в файле представляет собой некую целостную сущность данных, достаточно реализовать чтение имени и возраста для такой строки, и прерывать чтение при обнаружении некорректных данных.
Это также позволит сократить количество медленных операций ввода/вывода (чтения файла).
List<Human> people = new ArrayList<>();
try (Scanner sc = new Scanner(file)) {
while (sc.hasNextLine()) {
String line = sc.nextLine().trim();
if (line.isEmpty()) { // пропускаем пустую строку
continue;
}
String[] parts = line.split("\\s+");
String name = parts[0]; // имя в первой части строки
int age = Integer.valueOf(parts[1]); // возраст во второй части
if (age < 0) {
throw new IllegalArgumentException("Неверный возраст в строке " + line);
}
people.add(new Human(name, age));
}
}
catch (FileNotFoundException e) {
System.out.println("Файл не найден.");
}
catch (IllegalArgumentException e) {
System.out.println("Некорректный входной файл");
}
System.out.println(people);
Логику обработки каждой строки можно переместить в отдельный метод parseHuman
, например, если допускается, что поля имени и возраста в данном файле находятся на разных позициях в строке:
Василий 25
30 Николай
Данный метод реализует следующий функционал:
- Разобьёт входную строку по определённому разделителю
- Проверит наличие ровно двух полей в строке, если окажется не два поля, будет выброшено исключение
- Проверит, содержит ли строка поля имени и возраста в нужном формате (проверка на отрицательное значение станет не нужна), и выбросит исключение при необходимости
- Вернёт экземпляр класса
Human
, содержащий проверенные данные.
private static final String VALID_NAME = "\\p{L}+";
private static final String VALID_AGE = "\\d{1,3}";
private static Human parseHuman(String line) {
String[] parts = line.split("\\s+");
if (parts.length != 2) {
throw new IllegalArgumentException("Строка не содержит два поля: " + line);
}
String name;
int age;
if (parts[0].matches(VALID_NAME) && parts[1].matches(VALID_AGE)) {
name = parts[0];
age = Integer.valueOf(parts[1]);
} else if (parts[1].matches(VALID_NAME) && parts[0].matches(VALID_AGE))
name = parts[1];
age = Integer.valueOf(parts[0]);
} else {
throw new IllegalArgumentException("Некорректная строка: " + line);
}
return new Human(name, age);
}
Здесь регулярка "\\p{L}+"
проверит, что имя является непустой последовательностью любых букв, и соответственно "\\d{1,3}"
-- что возраст содержит непустую последовательность не более трёх цифр (без знака!).
Соответственно, логика кода для чтения файла сведётся к вызову указанного метода для каждой строки:
List<Human> people = new ArrayList<>();
try (Scanner sc = new Scanner(file)) {
while (sc.hasNextLine()) {
String line = sc.nextLine().trim();
if (!line.isEmpty())
people.add(parseHuman(line));
}
}
catch (FileNotFoundException e) {
System.out.println("Файл не найден.");
}
catch (IllegalArgumentException e) {
System.out.println("Некорректный входной файл");
}
System.out.println(people);