Создать объекты из списка строк с их элементами в качестве параметров
Windows 10;00001;2000;20;Microsoft
USB Flash Drive;20021;500;100;Samsung
Dell x-01;200232;1000;Notebook Dell;10;Dell
Dell od-1;3449;700;Monitor Dell;15;Dell
Asus x50m;4290;500;Notebook Asus;3;Asus
Читаю линии в списке, с помощью String split создаю массив строк. Создаю объекты new Product(), сеттерами поочередно внося строки в качестве параметров и приводя некоторые из них к необходимому типу.
В первом случае (строка Windows) все хорошо, во втором случае тоже, начиная со строки Dell и ниже есть дополнительная запись аля Notebook Dell, которую надо удалить или пропустить, чтобы корректно внести данные в конструктор. Я написал следующий код, благодаря которому все работает без лишней записи. Помогите добавить обработку:
private List<Product> getParsedList(List<String> listOfStrings) {
List<Product> parsedList = new ArrayList<>();
for (String line : listOfStrings) {
String[] productFields = line.split(";");
Product product = new Product();
product.setName(productFields[0]);
product.setUniqueNumber(productFields[1]);
Integer price = Integer.parseInt(productFields[2]);
product.setPrice(price);
Integer count = Integer.parseInt(productFields[3]);
product.setCount(count);
product.setProduction(productFields[4]);
parsedList.add(product);
}
return parsedList;
}
И можно ли вообще добавить итерацию к элементам массива?
Ответы (1 шт):
Если структура строки более-менее известна и определена, можно построить регулярное выражение с именованными группами, в котором будет пропущена дополнительная колонка или несколько колонок, и тогда можно будет вычитать данные после сопоставления строки заданному шаблону.
Шаблон может быть таким, группа (?<empty1>[^;]+;)* между группами price и count, содержащими целые числа, является необязательной и может содержать несколько колонок:
private static Pattern PRODUCT = Pattern.compile(
"(?<name>[^;]*);(?<id>[^;]*);(?<price>\\d+);(?<empty1>[^;]+;)*(?<count>\\d+);(?<production>[^;]*).*"
);
Допустим, что класс Product имеет конструктор со всеми необходимыми параметрами (например, сгенерированный при помощи Lombok аннотаций @Builder или @AllArgsConstructor), тогда данный метод можно переписать так:
private static Pattern PRODUCT = Pattern.compile(
"(?<name>[^;]*);(?<id>[^;]*);(?<price>\\d+);(?<empty1>[^;]+;)*(?<count>\\d+);(?<production>[^;]*).*"
);
private static List<Product> getParsedList(List<String> listOfStrings) {
return listOfStrings
.stream() // Stream<String>
.map(PRODUCT::matcher) // Stream<Matcher>
.filter(Matcher::matches) // выбрать совпавшие строки
.map(m -> new Product(
m.group("name"),
m.group("id"),
Integer.parseInt(m.group("price")),
Integer.parseInt(m.group("count")),
m.group("production")
)) // Stream<Product>
.collect(Collectors.toList());
}
Тест (добавлена еще одна колонка после Notebook Dell):
List<String> data = Arrays.asList(
"Windows 10;00001;2000;20;Microsoft",
"USB Flash Drive;20021;500;100;Samsung",
"Dell x-01;200232;1000;Notebook Dell;Another column;10;Dell",
"Dell od-1;3449;700;Monitor Dell;15;Dell",
"Asus x50m;4290;500;Notebook Asus;3;Asus"
);
List<Product> products = getParsedList(data);
products.forEach(System.out::println);
Результат:
Product(name=Windows 10, uniqueNumber=00001, price=2000, count=20, production=Microsoft)
Product(name=USB Flash Drive, uniqueNumber=20021, price=500, count=100, production=Samsung)
Product(name=Dell x-01, uniqueNumber=200232, price=1000, count=10, production=Dell)
Product(name=Dell od-1, uniqueNumber=3449, price=700, count=15, production=Dell)
Product(name=Asus x50m, uniqueNumber=4290, price=500, count=3, production=Asus)
Вариант с обычным for циклом:
private static List<Product> getParsedList(List<String> listOfStrings) {
List<Product> parsedList = new ArrayList<>();
for (String line : listOfStrings) {
Matcher matcher = PRODUCT.matcher(line);
if (matcher.matches()) {
parsedList.add(new Product(
matcher.group("name"),
matcher.group("id"),
Integer.parseInt(matcher.group("price")),
Integer.parseInt(matcher.group("count")),
matcher.group("production")
));
System.out.println("empty: " + matcher.group("empty1"));
}
}
return parsedList;
}