MultiValuedMap:多值Map
一个key可对应多个值,内部的数据结构逻辑交给它去维护。
我们平时使用的Map<String,List<Long>>这种数据结构,就可以被这种代替,使用起来非常方便
ArrayListValuedHashMap
见名之意,values采用ArrayList来存储
public static void main(String[] args) { MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>(); map.put("key1", "value1"); System.out.println(map); //{key1=[value1]} map.put("key1", "value11111"); System.out.println(map); //{key1=[value1, value11111]} Collection<String> values = map.values(); System.out.println(values); //[value1, value11111] //map.remove("key1"); //System.out.println(map); //{} //强悍 可以直接干掉values里的某一个值 map.removeMapping("key1", "value1"); System.out.println(map); //{key1=[value11111]} //一次性放多个value map.putAll("key2", Arrays.asList("fang", "shi", "xiang")); System.out.println(map); //{key1=[value11111], key2=[fang, shi, xiang]} //get方法 返回List Collection<String> collection = map.get("key2"); MultiSet<String> keys = map.keys(); Set<String> strings = map.keySet(); System.out.println(keys); //[key1:1, key2:3] //后面的数字表示对应的value的数量 System.out.println(strings); //[key1, key2] System.out.println(map.size()); //4 注意此处的size,是所有value的size 不是key的 System.out.println(collection); //[fang, shi, xiang] }
HashSetValuedHashMap
基本用法同上,但是很显然values用set去存储。那就无序,但是去重了
这些多值的Map的key,都是采用HashMap的结构存储的
MultiMapUtils提供一些基础工具方法:emptyMultiValuedMap、unmodifiableMultiValuedMap、newListValuedHashMap、getValuesAsSet、getValuesAsList等等
MultiSet
set我们都知道,它是无序的,并且是不允许出现重复元素的。
但有些场景我们不需要顺序,但是我们需要知道指定key出现的个数(比如每样产品ID对应的剩余数量这种统计信息),那么用MultiSet统计是一个很好的方案
HashMultiSet
底层实现原理为HashMap和MutableInteger
public static void main(String[] args) { MultiSet<String> set = new HashMultiSet<>(); set.add("fang"); set.add("fang"); set.add("shi"); set.add("xiang"); set.add("xiang"); set.add("xiang"); //我们发现此set是无序的,但是允许了重复元素的进入 并且记录了总数 System.out.println(set); //[shi:1, xiang:3, fang:2] System.out.println(set.size()); //6 = 1+3+2 //批量添加 一些字就添加N个 set.add("test",5); System.out.println(set); //[test:5, shi:1, xiang:3, fang:2] //移除方法 System.out.println(set.getCount("fang")); //2 set.remove("fang"); //此移除 一次性只会移除一个 System.out.println(set.getCount("fang")); //1 //一次性全部移除 N个 set.remove("xiang", set.getCount("xiang")); System.out.println(set.getCount("xiang")); //0 已经被全部移除了 //removeAll 吧指定的key,全部移除 set.removeAll(Arrays.asList("fang","shi","xiang","test")); System.out.println(set); //[] }
PredicatedMultiSet 使用较少,不做讲解
BoundedCollection:有限制的集合
继承自Collection,他提供了一些列的有用的实现
FixedSizeList:固定长度大小的List
public static void main(String[] args) { FixedSizeList<String> c = FixedSizeList.fixedSizeList(Arrays.asList("fang", "shi", "xiang")); System.out.println(c); //[fang, shi, xiang] System.out.println(c.size()); //3 //c.remove("fang"); //java.lang.UnsupportedOperationException: List is fixed size //c.add("fang"); //UnsupportedOperationException: List is fixed size //虽然不能增加和删除 但可以改 c.set(2, "heng"); System.out.println(c); //[fang, shi, heng] System.out.println(c.get(2)); //BoundedCollection提供的两个方法 c.isFull(); //如果是FixedSizeList 永远返回true 因为大小肯定是固定的 c.maxSize(); //值同size()方法 }
UnmodifiableBoundedCollection:不能修改的List
CircularFifoQueue:环形的先进先出队列
当达到指定的size长度后,符合FIfo先进先出的原则被环形覆盖
public static void main(String[] args) { CircularFifoQueue<String> c = new CircularFifoQueue<>(3); // 这个siz二和MaxSize就有差异化了 System.out.println(c.size()); //0 System.out.println(c.maxSize()); //3 c.add("fang"); c.add("shi"); c.add("xiang"); //我们发现虽然长度是3 但是因为循环的特性 再添加一个并不会报错 而是 c.add("heng"); System.out.println(c); //[shi, xiang, heng] // 继续添加 就会把前面的继续挤出来 满员了之后,符合先进先出的原则 c.add("heng2"); c.add("heng3"); System.out.println(c); //[heng, heng2, heng3] }
BoundedMap:
FixedSizeMap
public static void main(String[] args) { FixedSizeMap<String, String> m = FixedSizeMap.fixedSizeMap(new HashMap<String, String>() {{ put("fang", "a"); put("shi", "b"); put("xiang", "c"); }}); System.out.println(m); //{shi=b, xiang=c, fang=a} System.out.println(m.size()); //3 //不能再往里面添加数据了 //m.put("aaa", "aaa"); //java.lang.IllegalArgumentException: Cannot put new key/value pair - Map is fixed size //在我没有改变长度的情况下 是可以修改的 m.put("fang", "aaaaaaaa"); System.out.println(m); //{shi=b, xiang=c, fang=aaaaaaaa} }
FixedSizeSortedMap
区别:底层采用SortedMap
LRUMap
底层是LRU算法
LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
public static void main(String[] args) { LRUMap<Object, Object> map = new LRUMap<>(3); System.out.println(map); //{} System.out.println(map.size()); //0 System.out.println(map.maxSize()); //3 System.out.println(map.isFull()); //false map.put("fang", "a"); map.put("shi", "b"); map.put("xiang", "c"); System.out.println(map); //{fang=a, shi=b, xiang=c} System.out.println(map.size()); //3 System.out.println(map.maxSize()); //3 System.out.println(map.isFull()); //true //虽然满了 但还是可以往里面塞数据 如果我们都没有get使用过 那就从后往前挤出来吧 //map.put("heng", "heng"); //map.put("heng22", "heng22"); //System.out.println(map); //{xiang=c, heng=heng, heng22=heng22} //System.out.println(map.size()); //3 //System.out.println(map.maxSize()); //3 //System.out.println(map.isFull()); //true //我此处多次使用xiang这个key 我们会发现 xiang这个key就不会被挤出来 map.get("xiang"); map.get("xiang"); map.put("heng", "heng"); map.put("heng22", "heng22"); System.out.println(map); //{xiang=c, heng=heng, heng22=heng22} System.out.println(map.size()); //3 System.out.println(map.maxSize()); //3 System.out.println(map.isFull()); //true }
SingletonMap
public static void main(String[] args) { SingletonMap<String, String> map = new SingletonMap<>(); System.out.println(map); //{null=null} //size已经是1了 System.out.println(map.size()); //1 System.out.println(map.maxSize()); //1 //哪怕一个都没有 也不能设置值 //map.put("one","one"); //Cannot put new key/value pair - Map is fixed size singleton //虽然不能再放key 但可以改值 map.setValue("xiang"); //{null=xiang} System.out.println(map); //一般建议在构造的时候,就给key和value赋值 如下: map = new SingletonMap<>("fang","shixiang"); System.out.println(map); //{fang=shixiang} }
GrowthList LazyList :list自增长效果
GrowthList修饰另一个列表,可以使其在因set或add操作造成索引超出异常时无缝的增加列表长度,可以避免大多数的IndexOutOfBoundsException。
public static void main(String[] args) { List<String> src = new ArrayList<>(); src.add("11"); src.add("22"); src = GrowthList.growthList(src); System.out.println(src); //经过GrowthList.growthList一修饰后 这个list能够最大程度的避免空数组越界问题 有时候还是挺有用的 // 索引超出,自动增长 src.set(4, "44"); System.out.println(src); //[11, 22, null, null, 44] }
备注:LazyList修饰另一个列表,当调用get方法时,如果索引超出列表长度,列表会自动增长,我们可以通过一个工厂获得超出索引位置的值。LazyList和GrowthList都可以实现对修饰的列表进行增长,但是LazyList发生在get时候,而GrowthList发生在set和add时候,我们也可以混合使用这两种列表。
SetUniqueList
SetUniqueList实现了一个不允许重复元素的列表,有点和Set类似。但是由有List,保证了顺序
public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("fang"); list.add("shi"); list.add("shi"); list.add("xiang"); System.out.println(list); //[fang, shi, shi, xiang] //完美实现去重 且还完美保证了顺序 list = SetUniqueList.setUniqueList(list); System.out.println(list); //[fang, shi, xiang] // 但是需要注意 因为已经是SetUniqueList 类型了 这个时候add相同元素就不再好使了 list.add("shi"); System.out.println(list); //[fang, shi, xiang] }
我表示这个List在我们既希望去重,有需要保持原来顺序的时候,特别特别好用。装饰一下就行,使用也非常方便
TreeList
TreeList实现了优化的快速插入和删除任何索引的列表。这个列表内部实现利用树结构,确保所有的插入和删除都是O(log n)。
public static void main(String[] args) { List<String> list = new TreeList<>(); list.add("fang"); list.add("shi"); list.add("shi"); list.add("xiang"); System.out.println(list); //[fang, shi, shi, xiang] }