Почему обновляются данные во всех Map

180
01 октября 2018, 10:10

Не могу понять, каким образом у меня обновляются данные во всех трех мапах?

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, что не должно быть. Каким образом это происходит-то?

Answer 1

Потому что коллекции хранят ссылки на объекты, а не сами объекты. Если вы создаёте два отображения

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));

Подозреваю, что в вашем случае стримы могут пригодиться не только для создания глубокой копии, но и для сокращения всего многословного метода с квадратичным алгоритмом до пары строк с существенно меньшим потреблением памяти и циклов процессора.

Answer 2

пришлось сделать вот так

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);
    }

Никогда не думал, что столкнусь с таким :) И то что скопировать мапу не так просто

READ ALSO
Где найти jar для support-v4

Где найти jar для support-v4

В Intellij Idea 20182 в android-проекте в коде объявлена переменная типа android

135
Процессор в Spring Batch - Java EE

Процессор в Spring Batch - Java EE

у меня есть структура в Spring Batch1

168
Можно ли над методом рест-контроллера ставить аннотацию @Transactional?

Можно ли над методом рест-контроллера ставить аннотацию @Transactional?

Можно ли над методом рест-контроллера ставить аннотацию @Transactional? Будут ли проблемы, если одновременно по этому URL одновременно будут пытаться...

177
FileOutputStream запись в файл

FileOutputStream запись в файл

При записи текста каждый раз создается новый файл "buterbrodtxt"

225