перевести цикл в стрим
Допустим, есть такой кусок кода:
public Set<Map<String, Object>> changeValues(String[] newValues, Set<Map<String, Object>> set) {
for (String newValue : newValues) {
String filterOperation = newValue.replaceAll("[^!=><%]", "");
String filterColumnName = newValue.substring(0, newValue.indexOf(filterOperation)).trim();
String filterColumnValue = newValue.substring(newValue.indexOf(filterOperation) + 1);
}
Полученные данные я бы хотел обновить в LinkedHasSet<Map<String,Object>>.
На данный момент это выглядит примерно так:
set.
stream().
filter(x->x.containsKey(filterColumnValue)).
forEach(x -> x.put(
filterColumnName,
ConverterClass.getConvertionMap().get(filterColumnName).apply(filterColumnValue)
));
Строка
ConverterClass.getConvertionMap().get(filterColumnName).apply(filterColumnValue)
просто преобразует filterColumnValue из типа String к нужному типу (Long/Double), и кладет в виде Object в наш set.
Т.е по сути получается так:
set.
stream().
filter(x->x.containsKey(filterColumnName)).
forEach(x -> x.put(filterColumnName, (Double/Long)filterColumnValue));
Весь код выглядит так:
for (String newValue : newValues) {
String filterOperation = newValue.replaceAll("[^!=><%]", "");
String filterColumnName = newValue.substring(0, newValue.indexOf(filterOperation)).trim();
String filterColumnValue = newValue.substring(newValue.indexOf(filterOperation) + 1).trim();
set.forEach(x -> x.put(filterColumnName, (Double/Long)filterColumnValue));
}
Есть ли какой-нибудь способ перевести весь цикл и вставку данных в коллекцию set в один стрим?
Мой подход мне не нравится, ведь для каждого нового значения newValue мне придется по новому получать итератор (set.forEach), и мне кажется, что можно как-то все сделать при помощи стрима.
Ответы (1 шт):
У вас есть некая коллекция строк, которую можно проще преобразовать в коллекцию пар имя=значение, по сути в мапу, например так:
Map<String, Object> map = newValues.stream()
.map(str -> str.split("[!=><%]")) // Stream<String[]>
.map(arr -> new String[]{ arr[0].trim(), arr[1].trim()})
.collect(Collectors.toMap(
arr -> arr[0], // имя
arr -> ConverterClass.getConvertionMap().get(arr[0]).apply(arr[1]), // значение
(v1, v2) -> v1, // функция слияния на случай конфликтов
LinkedHashMap::new
));
Здесь используется метод String::split для разбиения строки по делимитеру.
Затем для заданного множества set можно будет применить мапу с предыдущего шага как предложил @Byb в первом комментарии:
set.forEach(m -> m.putAll(map));
Если нужно только заменить значения, существующие в мапах внутри set, можно использовать метод Map::replaceAll, в который нужно передать ссылку на метод в экземпляре новой мапы map::getOrDefault:
// set.forEach(m -> m.replaceAll((k, v) -> map.getOrDefault(k, v)));
set.forEach(m -> m.replaceAll(map::getOrDefault));