【小家java】Java之Apache Commons-Collections4使用精讲(Bag、Map、List、Set全覆盖)(中)

简介: 【小家java】Java之Apache Commons-Collections4使用精讲(Bag、Map、List、Set全覆盖)(中)

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]
    }


相关文章
|
19天前
|
存储 Java API
Java交换map的key和value值
通过本文介绍的几种方法,可以在Java中实现Map键值对的交换。每种方法都有其优缺点,具体选择哪种方法应根据实际需求和场景决定。对于简单的键值对交换,可以使用简单遍历法或Java 8的Stream API;对于需要处理值不唯一的情况,可以使用集合存储或Guava的Multimap。希望本文对您理解和实现Java中的Map键值对交换有所帮助。
23 1
|
27天前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第19天】本文介绍了Java编程中重要的数据结构——Map,通过问答形式讲解了Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的使用和性能优化技巧,适合初学者和进阶者学习。
44 4
|
27天前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
51 3
|
27天前
|
存储 Java API
详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
【10月更文挑战第19天】深入剖析Java Map:不仅是高效存储键值对的数据结构,更是展现设计艺术的典范。本文从基本概念、设计艺术和使用技巧三个方面,详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
45 3
|
27天前
|
存储 缓存 安全
在Java的Map家族中,HashMap和TreeMap各具特色
【10月更文挑战第19天】在Java的Map家族中,HashMap和TreeMap各具特色。HashMap基于哈希表实现,提供O(1)时间复杂度的高效操作,适合性能要求高的场景;TreeMap基于红黑树,提供O(log n)时间复杂度的有序操作,适合需要排序和范围查询的场景。两者在不同需求下各有优势,选择时需根据具体应用场景权衡。
30 2
|
27天前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
24 2
|
27天前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
27 1
|
12天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
8天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
28 9
|
11天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####

推荐镜像

更多