需要实现一个 key 能保存多个 value 的 map,一个键可以对应多个值。
这样多存储一些 key 对应的 value,方便业务中使用。
比如,保存用户每个小时内登陆的次数,用这样的 map ,就比在 HashMap 的 value 里存 时间和登陆次数 拼接的字符串更方便。
需要的效果是:
user1 [2019-03-09 22:00:00, 10次]
user2 [2019-03-09 22:00:00, 8次]
上网搜“一个 key 保存多个 value 的 map”,发现有的博客里说可以用 IdentityHashMap。
可是我试了一下,发现没实现我要的功能。
继续搜,找到一种解决方法:https://www.cnblogs.com/jiadp/p/9335437.html
这篇博客里,作者将 LinkedHashMap 的 value 替换成 List<Object> 来实现这样的功能。
只不过这篇博客里的 LinkedMultiValueMap 实现的是 interface MultiValueMap 这样的接口,用起来稍微有些不方便。
我在这篇博客的基础上做了一些修改,让它实现了常见的 Map 接口,用起来更方便一些。
我修改后代码如下:
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
/** 一个 Key 保存多个 Value 的 Map,一个键可以对应多个值
* 将 LinkedHashMap 的 value 替换成 List<Object> 来实现这样的功能
*/
public class MultiValueMap<K, V> implements Map<String, Object>{
//
private Map<String, List<Object>> sourceMap =
new LinkedHashMap<String, List<Object>>();
public MultiValueMap(){}
//
public void put(String key, List<Object> values){
// 遍历添加进来的 List 的 Value,调用上面的 put(K, V) 方法添加
for(Object value : values){
put(key, value);
}
}
//
public void set(String key, Object value){
// 移除这个 Key,添加新的 Key-Value
sourceMap.remove(key);
put(key, value);
}
//
public void set(String key, List<Object> values){
// 移除 Key,添加 List<V>
sourceMap.remove(key);
put(key, values);
}
//
public void set(Map<String, List<Object>> map){
// 移除所有值,遍历 Map 里的所有值添加进来
sourceMap.clear();
sourceMap.putAll(map);
}
//
public void clear(){
sourceMap.clear();
}
//
public Set<String> keySet(){
return sourceMap.keySet();
}
//
public List<Object> values(){
// 创建一个临时 List 保存所有的 Value
List<Object> allValues = new ArrayList<>();
// 遍历所有的Key的Value添加到临时List
Set<String> keySet = sourceMap.keySet();
for(Object key : keySet){
allValues.addAll(sourceMap.get(key));
}
return allValues;
}
//
public List<Object> getValues(Object key){
return sourceMap.get(key);
}
//
public Object getValue(String key, int index){
List<Object> values = sourceMap.get(key);
if(values != null && index < values.size()){
return values.get(index);
}
return null;
}
//
public int size(){
return sourceMap.size();
}
//
public boolean isEmpty(){
return sourceMap.isEmpty();
}
//
public boolean containsKey(Object key){
return sourceMap.containsKey(key);
}
//
public Object put(String key, Object value){
if(key != null){
// 如果没有就创建一个 List 并添加 Value
if(!sourceMap.containsKey(key)){
List<Object> list = new ArrayList<Object>();
sourceMap.put(key, list);
}
boolean re = sourceMap.get(key).add(value);
return re;
}else{
return false;
}
}
//
public Object get(Object key){
return sourceMap.get(key);
}
//
public Object remove(Object key){
return sourceMap.remove(key);
}
//
public void putAll(Map map){
for(Object entry : map.entrySet()){
Map.Entry<String, Object> en = (Map.Entry<String, Object>) entry;
String key = en.getKey();
Object value = en.getValue();
if(value instanceof List){
List<Object> values = (List<Object>) value;
put(key, values);
}else{
put(key, value);
}
}
}
//
public boolean containsValue(Object value){
List<Object> values = values();
if(value instanceof List){
List<Object> aList = (List<Object>) value;
// Returns true if this list contains all of the elements of the specified collection.
return values.containsAll(aList);
}else{
return values.contains(value);
}
}
//
public Set entrySet(){
return sourceMap.entrySet();
}
// ------------------------ 测试这个类 ------------------------------
/** 获得当前日期的字符串,格式 yyyy-MM-dd HH:00:00 */
public static String getStringTimeToHour(){
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
return fmt.format(new Date());
}
/** 生成一个随机整数,范围从 1 到 10 */
public static int getRandomIntRangeFrom1To10(){
int random = new Random().nextInt(10) + 1;
return random;
}
// main
public static void main(String[] a){
String id1 = 123 + "";
String id2 = 124 + "";
String id3 = 125 + "";
String id4 = 126 + "";
Map<String, Object> map6 = new MultiValueMap<>();
// 测试 put
map6.put(id1, "Wade");
map6.put(id1, getStringTimeToHour());
map6.put(id1, getRandomIntRangeFrom1To10());
map6.put(id2, "Ibrahimovic");
map6.put(id2, getStringTimeToHour());
map6.put(id2, getRandomIntRangeFrom1To10());
map6.put(id3, "Dejokovic" );
map6.put(id3, getStringTimeToHour());
map6.put(id3, getRandomIntRangeFrom1To10());
map6.put(id4, "Van Persie");
map6.put(id4, getStringTimeToHour());
map6.put(id4, getRandomIntRangeFrom1To10());
// 测试 keySet。用 keySet 遍历,并打印
for(String key : map6.keySet()){
List<Object> values = (List<Object>) map6.get(key);
for(Object value : values){
System.out.println(key + ": " + value);
}
System.out.println();
}
// 测试 putAll
Map<String, Object> map = new HashMap<>();
List<Object> valuesF = new ArrayList<>();
String idF = "127";
//map.put(idF, "Figo");
//map6.putAll(map);
valuesF.add("Figo");
valuesF.add(getStringTimeToHour());
valuesF.add(getRandomIntRangeFrom1To10());
map.put(idF, valuesF);
map6.putAll(map);
// 测试 containsValue
System.out.println( map6.containsValue("Figo"));
System.out.println( map6.containsValue(valuesF));
System.out.println();
// 测试 entrySet。用 entrySet 遍历,并打印
for(Object entry : map6.entrySet()){
Map.Entry<String, Object> en = (Map.Entry<String, Object>) entry;
String key = en.getKey();
Object value = en.getValue();
System.out.println(key + " " + value.toString());
}
System.out.println();
// 测试 get
System.out.println( map6.get( "127" ) );
}
}
打印结果:
123: Wade
123: 2019-03-09 22:00:00
123: 10
124: Ibrahimovic
124: 2019-03-09 22:00:00
124: 8
125: Dejokovic
125: 2019-03-09 22:00:00
125: 8
126: Van Persie
126: 2019-03-09 22:00:00
126: 6
true
true
123 [Wade, 2019-03-09 22:00:00, 10]
124 [Ibrahimovic, 2019-03-09 22:00:00, 8]
125 [Dejokovic, 2019-03-09 22:00:00, 8]
126 [Van Persie, 2019-03-09 22:00:00, 6]
127 [Figo, 2019-03-09 22:00:00, 9]
[Figo, 2019-03-09 22:00:00, 9]
------------------------------------------------
如果这样添加:
String id211 = "212";
List<Object> values2a = new ArrayList<>();
values2a.add( "2019-3-1 01:00:00" );
values2a.add( getRandomIntRangeFrom1To10() );
map6.put( id211, values2a );
List<Object> values2b = new ArrayList<>();
values2b.add( "2019-3-1 02:00:00" );
values2b.add( getRandomIntRangeFrom1To10() );
map6.put( id211, values2b );
打印结果就是: 212 [[2019-3-1 01:00:00, 8], [2019-3-1 02:00:00, 3]]
可以起到保存时间段和登陆次数的作用。