Не могу понять, каким образом у меня обновляются данные во всех трех мапах?
public void updateMap(Map<String, WagonFinalInfo> map, String wagons, String rates, String tariffs) {
List<WagonRateAndTariff> listRateAndTariff = PrepareDateForInsert.fillListForUpdate(wagons, rates, tariffs);
Map<String, WagonFinalInfo> oldMap = new HashMap<>(map);
Map<String, WagonFinalInfo> tempNewMap = new HashMap<>(map);
logger.debug("listRateAndTariff: {}", listRateAndTariff);
for (Map.Entry<String, WagonFinalInfo> _map: tempNewMap.entrySet()) {
for (WagonRateAndTariff list : listRateAndTariff) {
if (_map.getKey().equals(list.getNumberOfWagon())) {
if (_map.getValue().getRate() != (Double) list.getRate()) {
_map.getValue().setRate(list.getRate());
}
if (_map.getValue().getTariff() != (Double) list.getTariff()) {
_map.getValue().setTariff(list.getTariff());
}
}
}
}
newMapWagonFinalInfo.putAll(tempNewMap);
logger.info("newMapWagonFinalInfo: {}, oldMap: {}", newMapWagonFinalInfo, oldMap);
classHandlerInsertRateOrTariff.insertDate(newMapWagonFinalInfo, oldMap);
calculateYield(newMapWagonFinalInfo);
}
Обновляют вроде как в tempNewMap
, а на выходе получаю обновления и в map
и в oldMap
, что не должно быть. Каким образом это происходит-то?
Потому что коллекции хранят ссылки на объекты, а не сами объекты. Если вы создаёте два отображения
Map<String, SomeClass> first = new HashMap<>();
Map<String, SomeClass> second = new HashMap<>();
добавляете объект в первое
first.put('A', new SomeClass());
а потом "копируете" во второе
second.put('A', first.get('A'));
то объект в куче остаётся только один, а в отображение second добавляется ссылка на этот объект. Чтобы этого избежать нужно выполнить глубокое копирование, то есть создать в куче новый объект и перенести в него данные из старого. Хорошей практикой является возложение функции копирования объекта на него самого. Обычно это делается объявлением конструктора копирования:
class WagonFinalInfo {
// Поля и другие конструкторы
...
public WagonFinalInfo(WagonFinalInfo source) {
setNumberOfWagons(source.getNumberOfWagons());
// Копирование остальных данных
...
}
// Аксессоры и другие методы
...
}
И потом в том месте кода, где надо создать копию отображения
Map<String, WagonFinalInfo> newMap =
oldMap.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, WagonFinalInfo::new));
Подозреваю, что в вашем случае стримы могут пригодиться не только для создания глубокой копии, но и для сокращения всего многословного метода с квадратичным алгоритмом до пары строк с существенно меньшим потреблением памяти и циклов процессора.
пришлось сделать вот так
for (Map.Entry<String, WagonFinalInfo> _map: oldMap.entrySet()) {
String numberWagon = new String(_map.getKey());
WagonFinalInfo wagonFinalInfo = new WagonFinalInfo(
_map.getValue().getNumberOfWagon(),
_map.getValue().getCountCircleDays(),
_map.getValue().getDistanceEmpty(),
_map.getValue().getCurrentNameOfStationOfWagon(),
_map.getValue().getCurrentKeyOfStationOfWagon(),
_map.getValue().getNameOfStationDepartureOfWagon(),
_map.getValue().getKeyOfStationDepartureOfWagon(),
_map.getValue().getRoute(),
_map.getValue().getCargo(),
_map.getValue().getCargoType());
tempNewMap.put(numberWagon, wagonFinalInfo);
}
Никогда не думал, что столкнусь с таким :) И то что скопировать мапу не так просто
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
В Intellij Idea 20182 в android-проекте в коде объявлена переменная типа android
Можно ли над методом рест-контроллера ставить аннотацию @Transactional? Будут ли проблемы, если одновременно по этому URL одновременно будут пытаться...