HashMap:
//类声明 实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
}
是非线程安全的,只是用于单线程环境下
底层实现:
由数组+单链表/红黑树数据结构存储数据
存储的数据无序,随机存储
HashMap存数据的过程是:
HashMap内部维护了一个存储数据的Entry数组,HashMap采用链表解决冲突,每一个Entry本质上是一个单向链表。
当准备添加一个key-value对时,首先通过hash(key)方法计算hash值,然后通过indexFor(hash,length)
求该key-value对的存储位置,计算方法是先用hash&0x7FFFFFFF后,再对length取模,
这就保证每一个key-value对都能存入HashMap中,当计算出的位置相同时,由于存入位置是一个链表,
则把这个key-value对插入链表头。
HashTable
//类声明 实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {
Hashtable 中的方法都有Synchronize关键字修饰,所以时线程安全的
HashMap和HashTable的区别
//HashMap是线程不安全的
HashMap<String, Double> boxInfo = new HashMap<>();
//如果想线程安全,则new HashMap的时候这么写:如下
Map<String, Double> m = Collections.synchronizedMap(new HashMap<>());
参考:HashTable和HashMap的区别详解:https://www.cnblogs.com/williamjie/p/9099141.html
LinkedHashMap
//类声明 继承于HashMap,是基于HashMap和双向链表来实现的
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
在hashmap的基础上,用双链表实现:
1、双向链表只是为了保证put和get顺序,即存取数据的顺序一致
2、LinkedHashMap有序
3、LinkedHashMap是线程不安全的
LinkedHashMap应用场景:
当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了。
TreeMap的用法(主要是排序)
//类声明 默认的排序为升序,需改变排序则实现Comparator接口
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
//TreeMap
1、由红黑树算法实现的
2、是非线程安全的,和hashMap一样
业务需求,需要按时间进行升序展示数据信息:
map结构类似于这样:
private static Map<String, List<CapabilityStatMap>> cacheSlineCapabilityStatMap = new ConcurrentHashMap<>();
"data": {
"aa2994b5-441c-423e-a6ce-1ea717c7b013": [
{
"area_id": "",
"spec_id": "test_spec898",
"vpl_id": "test_spec898",
"tem_id": "tem20191211170800-2",
"day": "2019-12-31T00:00:00",
"dailyCapability": 8000.3,
"availableCapability": 0.0,
"beUsedCapability": 8000.3,
"sboxesInfoMap": {
"01ed2423-6fa3-4d76-a739-801fdfaa9833": {
"total": 8000.3,
"forget": 6240.3,
"used": 1760.0,
"ava": 0.0
}
}
}
]
}
自定义比较器
MapKeyComparator
package com.hierway.vslm.common.util;
import java.time.LocalDateTime;
import java.util.Comparator;
/**
* @Description
* @Author by mocar小师兄
* @Date 2019/12/20 11:40
**/
public class MapKeyComparator implements Comparator<LocalDateTime> {
@Override
public int compare(LocalDateTime o1, LocalDateTime o2) {
//参数o1,小于、等于或者大于o2 ,返回负整数、0或者正整数
//返回负数则o1在前,正数则o2在前
if (o1.isBefore(o2)){
return -1;
}else if (o1.isAfter(o2)){
return 1;
}else {
return 0;
}
}
}
排序的重要逻辑,在new TreeMap的时候,给构造器传一个自己自定义的比较器:
ArrayList<CapabilityStatMap> capabilityStatMaps = new ArrayList<>();
List<String> sids = sLineList.stream().map(SLine::getStreamLineId).collect(Collectors.toList());
for (String sid : sids) {
List<CapabilityStatMap> capabilityStatMapList = new ArrayList<>();
if (!CollectionUtils.isEmpty(getCacheSlineCapabilityStatMap())
&& getCacheSlineCapabilityStatMap().containsKey(sid)) {
capabilityStatMapList = getCacheSlineCapabilityStatMap().get(sid);
//合并
capabilityStatMaps.addAll(capabilityStatMapList);
} else {
continue;
}
}
//按查询时间过滤
List<CapabilityStatMap> capaFilter = capabilityStatMaps.stream().filter(capabilityStatMap -> (capabilityStatMap.getDay().isEqual(startTime) || capabilityStatMap.getDay().isAfter(startTime)) &&
(capabilityStatMap.getDay().isEqual(endTime) || capabilityStatMap.getDay().isBefore(endTime))).collect(Collectors.toList());
if (CollectionUtils.isEmpty(capaFilter)) {
logger.error("在时间:{} -- {} 内,没有查询到产能数据,{}", startTime,endTime,methodStr);
//return null;
throw new ApiException(ResultCode.NO_DATA_FOUND);
}
//按时间分组
Map<LocalDateTime, List<CapabilityStatMap>> localDateTimeListMap = capaFilter.stream().collect(Collectors.groupingBy(CapabilityStatMap::getDay));
//按时间排序 TreeMap
Map<LocalDateTime, List<CapabilityStatMap>> sortByLocalDateTimeMap = new TreeMap<>(new MapKeyComparator());
sortByLocalDateTimeMap.putAll(localDateTimeListMap);
红黑树参考: https://blog.csdn.net/cyywxy/article/details/81151104
LinkedHashMap和hashMap和TreeMap的区别: https://www.cnblogs.com/coder-lzh/p/10819627.html
总结:如何选择合适的Map
- HashMap可实现快速存储和检索,但其缺点是其包含的元素是无序的,这导致它在存在大量迭代的情况下表现不佳。
- LinkedHashMap保留了HashMap的优势,且其包含的元素是有序的。它在有大量迭代的情况下表现更好。
- TreeMap能便捷的实现对其内部元素的各种排序,但其一般性能比前两种map差。
- LinkedHashMap映射减少了HashMap排序中的混乱,且不会导致TreeMap的性能损失。