Я надеюсь, что у тебя все хорошо.
У меня есть две карты, и я хочу сохранить нулевые значения. Я знаю, что функция слияния не может управлять нулевыми значениями, но мне нужно сохранить нулевые данные и использовать двоичную операцию.
Как я могу управлять своим кодом, чтобы избежать NPE.
private Map<String, Object> mergeMaps(
Map<String, Object> map1, Map<String, Object> map2) {
return Stream.of(map1, map2)
.map(Map::entrySet)
.flatMap(Collection::stream)
.collect(
Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(v1, v2) -> v1 != null
&& StringUtils.isNotEmpty(v1.toString())
? v1
: v2
));
}
Пример тестового кода:
public static void main(String[] args) {
Map<String, Object> map1 = new HashMap<>();
map1.put("k1", null);
map1.put("k2", "2");
map1.put("k3", null);
Map<String, Object> map2 = new HashMap<>();
map2.put("k1", "1");
map2.put("k2", null);
map2.put("k3", null);
var result = mergeMaps(map1, map2);
System.out.println(result);
}
должно вывести что-то вроде {k1=1, k2=2, k3=null}; k1 был заменен на карту2, k2 остался из карты1, а k3 был null в обоих.
Большое спасибо.
Почему вы не можете просто иметь дело с нулями? (v1, v2) -> (v1 == null || v1.toString().isEmpty()) ? v2 : v1
Потому что Map.Entry::getValue вернуть NPE
@daniu это невозможно без использования Необязательно?
Где в документации сказано, что Map.Entry::getValue выбрасывает NPE? Эта функция сама по себе, конечно, не выбрасывает: она просто возвращает null, если значение равно null. Функция toMap выдает NPE, только если вы передаете null вместо Map.Entry::getValue. Неважно, вернется ли getValue()null.
@ k314159 Проблема в том, что Map#merge не может обрабатывать записи со значением null, которое используется в сборщике toMap.
@daniu Это было бы неправильное использование Optional. Я рекомендую против этого.
Ваш код не компилируется. Пожалуйста, удалите ненужную точку с запятой. Кроме этого, если ваш код выдает NPE, разве это не из v1.toString(), поскольку v1 может быть null согласно тому, что вы говорите? Объясните, пожалуйста, для чего вообще нужен StringUtils.isNotEmpty()? Без этой информации я не могу понять ваши требования?
@Bourg Я чувствую, что отрицательные голоса и придирчивые комментарии граничат с троллингом, но в них есть смысл; потребовалось время, чтобы понять, о чем вы спрашиваете и в чем проблема. Для будущих вопросов вам, вероятно, следует добавить код с примером ввода, показывающим проблему (как я это сделал в своем ответе).
@daniu Я не согласен с тем, что желание понять требования находится на грани придирок. Я проголосовал против и проголосовал за закрытие.
@daniu Я надеялся, что помог ФП улучшить вопрос, чтобы будущие читатели могли его понять. Я не вижу особой ценности в том, чтобы держать неясный вопрос при себе.
@Anonymous Да, как я уже сказал, твои точки зрения верны. Тем не менее, я думаю, что лучший подход — просто предоставить правильный пример: у вас есть права на редактирование, вы можете просто удалить лишнюю точку с запятой самостоятельно, это занимает меньше времени, чем указание OP сделать это. Кроме того, я уже удалил упомянутый вами NPE, так что этот пункт больше не актуален, как и сопровождающее его закрытое голосование. Оставляет отсутствующие входные данные теста, что является лучшим моментом, но доступно в моем ответе; Я могу перенести это на вопрос, но не понимаю, как это делает пост в целом недействительным.
Бург, лучшее, что вы могли бы сделать для пользователей Stack Overflow, — это по-прежнему отредактировать свой вопрос и полностью прояснить, как вы хотите расставить приоритеты (а) нулевых значений (б) пустых строк (в) объектов, возвращающих пустую строку из своего метода toString и (d) другие объекты (обычные объекты), происходящие из значений двух карт. Бонусы для вас включают в себя: существующий ответ может быть улучшен, я отзову свой отрицательный голос и проголосую за повторное открытие, что в конечном итоге может позволить вам получить больше ответов.
@daniu Спасибо за улучшение вопроса. Он явно улучшился, но все еще неясен, и у меня нет информации, необходимой для разъяснения, поэтому я не могу ничего сделать дальше, извините.




я бы пошел на
Map<String, Object> mergeMaps(Map<String, Object> map1,
Map<String, Object> map2) {
Map<String, Object> result = new HashMap<>(map1);
map2.forEach((k, v) -> {
var value = result.get(k);
if (value == null || value.toString().isEmpty()) {
result.put(k, v);
}
});
return result;
}
Что отлично работает для тестового примера.
Если map1 имеет запись "k1": "" (значение представляет собой нулевую строку), то ОП хочет, чтобы объединенная карта содержала значение из map2. Ваше решение этого не делает.
@ k314159 да, тривиально, скорректировано.
Теперь это хороший ответ. Хотя я бы поменял result.put(map2.get(k)); на result.put(v);.
Спасибо @daniu и k314159 за вашу помощь. Это хорошо для меня.
два голоса "за" и принято, но даже не компилируется :- / --- 1) отсутствует );; 2) put() нужны два аргумента; 3) отсутствует isNullOrEmpty(Object)
@ k314159 Если в map1 есть запись "k1": "" (…), то ОП хочет, чтобы объединенная карта содержала значение из map2. Нет, нигде в ОП этого не сказано.
@Аноним, да, они это сделали: StringUtils.isNotEmpty(v1.toString()) ? v1 : v2
@ k314159 Они этого не сделали. Они говорили о нулях. Вызов, который вы цитируете, завершится неудачно с NullPointerException, v1 имеет значение null, поэтому он никогда не работал, и то, что ОП намеревался с ним сделать, зависит от интерпретации.
Используйте
Map<String, Optional<Object>>