У меня есть Map<String, String>
ключ String
- это не что иное, как числовое значение, например "123" и т.д. Я получаю числовое значение, потому что эти значения поступают из пользовательского интерфейса в моем компоненте JSF. Я не хочу менять контракт с компонентом пользовательского интерфейса.
Теперь я хотел бы создать Map<Long, String>
на основе вышеперечисленного Map
, я видел несколько методов transform
в классе Maps
, но все они фокусируются на преобразовании, а не на ключе.
Есть ли лучший способ конвертировать Map<String, String>
в Map<Long, String>
?
Как преобразовать карту <String, String> в карту <Long, String>? (опция: использование гуавы)
Ответ 1
ОБНОВЛЕНИЕ для Java 8
Вы можете использовать потоки, чтобы сделать это:
Map<Long, String> newMap = oldMap.entrySet().stream()
.collect(Collectors.toMap(e -> Long.parseLong(e.getKey()), Map.Entry::getValue));
Это предполагает, что все ключи являются допустимыми строковыми представлениями Long
s. Также вы можете столкнуться при трансформации; например, "0"
и "00"
оба соответствуют 0L
.
Я думаю, что вам придется перебирать карту:
Map<Long, String> newMap = new HashMap<Long, String>();
for(Map.Entry<String, String> entry : map.entrySet()) {
newMap.put(Long.parseLong(entry.getKey()), entry.getValue());
}
Этот код предполагает, что вы санировали все значения в map
(поэтому недопустимые длинные значения).
Я надеюсь, что есть лучшее решение.
РЕДАКТИРОВАТЬ
В Commons Collection-Utils я столкнулся с методом Поцарапайте это, это работает только для классов, которые реализуют CollectionUtils#transformedCollection(Collection, Transformer)
который выглядит так, как будто он может делать то, что вы хотите.Collection
.
Ответ 2
@Ответ Vivin правильный, но я считаю полезным объяснить, почему у Guava нет никакого способа разрешить вам преобразовать ключи Map
(или вообще преобразовать Set
).
Все методы Guava для преобразования и фильтрации создают ленивые результаты... функция/предикат применяется только тогда, когда это необходимо, когда объект используется. Они не создают копии. Из-за этого преобразование может легко нарушить требования Set
.
Скажем, например, у вас есть Map<String, String>
, который содержит как "1", так и "01" в качестве ключей. Они оба отличаются String
s, и поэтому Map
может легально содержать как клавиши. Если вы преобразуете их с помощью Long.valueOf(String)
, они оба сопоставляют значение 1
. Они больше не являются отдельными ключами. Это ничего не сломает, если вы создадите копию карты и добавите записи, потому что любые дубликаты клавиш будут перезаписывать предыдущую запись для этого ключа. Ленообразно преобразованный Map
, однако, не имел бы возможности использовать уникальные ключи и поэтому нарушил бы контракт Map
.
Ответ 3
Теперь вы можете использовать поток Java 8, карту, собирать, чтобы сделать это более понятным и понятным образом.
Map<String, String> oldMap
Map<Long, String> newMap = oldMap.entrySet().stream()
.collect(Collectors.toMap(entry -> Long.parseLong(entry.getKey()), Map.Entry::getValue));
Ответ 4
Здесь приведена обновленная версия одного из приведенных ниже ответов, чтобы сделать полученную карту неизменяемой (нет, она не использует Guava, просто Java 8):
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toMap;
...
newMap = oldMap.entrySet().stream().collect(collectingAndThen(
toMap((Map.Entry<String, String> entry) -> transformKey(entry.getKey()),
(Map.Entry<String, String> entry) -> transformValue(entry.getValue())),
Collections::unmodifiableMap)));
Ответ 5
Короткий ответ - нет, Guava не предоставляет этот вариант из коробки.
Простым способом будет что-то вроде ниже. Однако есть некоторые предостережения.
public static <K, V, L, W> Map<L, W> transformMap(Map<K, V> map, Function<K, L> keyFunction, Function<V, W> valueFunction) {
Map<L, W> transformedMap = newHashMap();
for (Entry<K, V> entry : map.entrySet()) {
transformedMap.put(
keyFunction.apply(entry.getKey()),
valueFunction.apply(entry.getValue()));
}
return transformedMap;
}
public static <K, V, L> Map<L, V> transformKeys(Map<K, V> map, Function<K, L> keyFunction) {
return transformMap(map, keyFunction, Functions.<V>identity());
}
Трансформаторы Guava все "ленивы" или основаны на просмотре. Я думаю, что для реализации трансформатора ключа карты вам понадобится двухсторонняя функция. Я понимаю, что есть конвертер, который находится в работе команды Guava, которая решила бы эту проблему.
Другая проблема, с которой вы столкнулись, заключается в том, что вам придется иметь дело с возможностью дублирования, чтобы быть "Jimmy-proof", еще одним принципом Guava. Один из способов справиться с этим - вернуть Multimap; другой - вызывать исключение, когда вы сталкиваетесь с дубликатами. То, что я бы не предложил, скрывает проблему, например. игнорируя последующие записи с дублирующимися ключами или перезаписывая новую запись дублирующимся ключом.
Ответ 6
Лучшее сообщение, чтобы предоставить готовые рабочие решения для этого, можно найти здесь:
Этот сайт показывает все 3 возможных случая:
- Карта → Карта
- Карта → Карта
- Карта → Карта