我有一个如下所示的数据模型:
class CustomField {
String key;
String value;
}
从我可以获得List<CustomField>
实例的API。密钥在列表中是唯一的,这意味着此集合确实应该是Map<String, String>
。在此列表上操作很麻烦,因为每个操作都需要迭代来检查现有密钥(CustomField不会实现等于)
如何创建Map<String, String>
&#34;视图&#34;在此列表的支持下,我可以使用Map界面对其进行操作吗?
我想要一个通用方法,例如:<T, K, V> Map<K, V> createMapBackedByList(List<T> list, BiFunction<K, V, T> elementMapper, Function<T, K> keyMapper, Function<T, V> valueMapper)
或类似的。
它将使用函数在列表元素和映射键和值之间进行映射。
这里重要的是我希望对地图的更改反映在基础列表中,这就是Streams API在这里不起作用的原因......
编辑:我无法修改API或CustomField类。
答案 0 :(得分:3)
简单:
自己编写
public class ListBackedMap<K, V> implements Map<K, V> {
在创作时需要某种List<Pair<K,V>>
;并且&#34;推迟&#34;那个。当然,这要求您的CustomField
类实现Pair
接口。 (你可能也需要发明)
(或者:您的新课程extends AbstractMap<K,V>
可以保护您的大部分工作)。
现在你的方法只返回一个这样的Map的实例。
换句话说:我不知道有一个符合您要求的内置包装器。但是自己实施一个应该是非常直接的。
编辑:鉴于OP无法更改CustomField
类,这是一个简单的助手,例如
interface <K, V> MapEntryAdapter {
K getKey();
V getValue();
}
将是必需的;以及知道如何从CustomField
的实例检索键/值的特定实现。在这种情况下,地图将由List<MapEntryAdapter<K, V>>
支持。
答案 1 :(得分:1)
我最终尝试自己实现它并将其基于AbstractList。它实际上比我第一次更容易......
public class ListBackedMap<T, K, V> extends AbstractMap<K, V> {
private final List<T> list;
private final BiFunction<K, V, T> keyValueToElement;
private final Function<T, K> elementToKey;
private final Function<T, V> elementToValue;
public ListBackedMap(List<T> list, BiFunction<K, V, T> keyValueToElement, Function<T, K> elementToKey, Function<T, V> elementToValue) {
this.list = list;
this.keyValueToElement = keyValueToElement;
this.elementToKey = elementToKey;
this.elementToValue = elementToValue;
}
@Override
public Set<Entry<K, V>> entrySet() {
return list.stream()
.collect(toMap(elementToKey, elementToValue))
.entrySet();
}
@Override
public V put(K key, V value) {
V previousValue = remove(key);
list.add(keyValueToElement.apply(key, value));
return previousValue;
}
public List<T> getList() {
return list;
}
}
它不是非常高性能(或线程安全),但它似乎做得很好。
示例:
List<CustomField> list = getList();
ListBackedMap<CustomField, String, String> map = new ListBackedMap<>(
list,
(key, value) -> new CustomField(key, value),
CustomField::getKey,
CustomField::getValue);