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

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

前言


这个库简化了你的代码,使它易写、易读、易于维护。它能提高你的工作效率,让你从大量重复的底层代码中脱身。


虽然JDK提供给我们的集合框架已经足够强大,基本能解决我们平时的绝大所述问题,并且效率还挺高。


本文针对于Apache提供的Collections4组件提供的一些特殊数据结构,通过例子解决一些实际问题的讲解。


® bag接口

® 固定大小的map、lru (最近最少使用算法)map和双重(dual)map

® 对象数组和map的迭代器

® map的multikey

® 大量的工具类,提供了使用api的快捷方式

® 封装器,对大多数类提供了自定义的方法


Bag


Bag继承自Collection接口,定义了一个集合,该集合会记录对象在集合中出现的次数。


假设你有一个包,包含{a, a, b, c}。调用getCount(a)方法将返回2,调用uniqueset()方法将返回{a, b, c}的set集合。


public interface Bag<E> extends Collection<E> {}


顾名思义,它是包的意思,所以也是拿来装数据的。


HashBag


HashBag使用HashMap作为数据存储,是一个标准的Bag实现。


    public static void main(String[] args) {
        Bag hashBag = new HashBag();
        String s1 = "s1";
        String s2 = "s2";
        hashBag.add(s1);
        hashBag.add(s1);
        //一次性放置多个元素
        hashBag.add(s2, 3);
        // 获得包中元素迭代器
        Iterator<?> iterator = hashBag.iterator();
        System.out.println("包中元素为:");
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        System.out.println("包中元素个数为:" + hashBag.size()); //5
        //下面两个特有的方法 使用起来较为方便
        System.out.println("包中entity1个数为:" + hashBag.getCount(s1)); //2
        System.out.println("去重后个数为:" + hashBag.uniqueSet().size()); //2
    }
结果输出:
包中元素为:
s1
s1
s2
s2
s2
包中元素个数为:5
包中entity1个数为:2
去重后个数为:2


TreeBag


TreeBag使用TreeMap作为数据存储,用法与HashBag类似,只是TreeBag会使用自然顺序对元素进行排序。


总结


使用的方式和List差不多,效果也大同小异。

场景:比如我们需要具体知道每个元素出现的次数的时候,并且实现快速去重,使用Bag会非常便捷


对应的BagUtils,能提供BagUtils.EMPTY_BAG、synchronizedBag、unmodifiableBag等编程同步、只读的快捷方法


BidiMap: 双重Map


使用双向映射,可以使用值查找键,并且可以使用键轻松查找值。(自然,它可以根绝key移除,也可以根据value移除)


该场景使用还是比较多的,比如一对一的映射关系,都可以使用这来存储。如果你使用HashMap,那你得维护两个,还是比较麻烦的


public interface BidiMap<K, V> extends IterableMap<K, V> {}


也是个普通的Map。继承IterableMap增加了一种迭代方式,例子里会有讲解


DualHashBidiMap


底层维护两个HashMap,一个正向,一个逆向来达到效果的。


    public DualHashBidiMap() {
        super(new HashMap<K, V>(), new HashMap<V, K>());
    }
  //把一个普通的Map转成BidiMap
    public DualHashBidiMap(final Map<? extends K, ? extends V> map) {
        super(new HashMap<K, V>(), new HashMap<V, K>());
        putAll(map);
    }


看个示例:


    public static void main(String[] args) {
        BidiMap<String, String> map = new DualHashBidiMap<>();
        map.put("key1", "value1");
        map.put("key2", "value2");
        map.put("key3", "value3");
        //多出来的一种遍历方式  还是分厂人性化的
        MapIterator<String, String> it = map.mapIterator();
        while (it.hasNext()) {
            it.next(); //此句话必须调用  返回的是key,效果同getKey,但必须调用
            System.out.println(it.getKey() + "---" + it.getValue());
        }
        System.out.println(map.get("key1")); //value1
        //根据value拿key
        System.out.println(map.getKey("value1")); //key1
        //这个方法是Map接口的
        System.out.println(map.getOrDefault("k", "defaultValue")); //defaultValue
        //返回一个逆序的视图  注意是视图
        BidiMap<String, String> inverseMap = map.inverseBidiMap();
        //根据key删除
        inverseMap.remove("key1");
        //根据value删除
        inverseMap.removeValue("value2");
        System.out.println(map); //{key1=value1, key2=value2, key3=value3}
        System.out.println(inverseMap); //{value2=key2, value1=key1, value3=key3}
    }
输出:
key1---value1
key2---value2
key3---value3
value1
key1
defaultValue
{key1=value1, key2=value2, key3=value3}
{value2=key2, value1=key1, value3=key3}

DualLinkedHashBidiMap

底层采用两个LinkedHashMap存储,其余同上


DualTreeBidiMap

底层采用两个TreeMap存储,其余同上


它不要求key和value都是实现了比较器接口的,但是自己可以自定义比较器接口传进去


TreeBidiMap


注意TreeBidiMap和DualTreeBidiMap的区别

TreeBidiMap采用是红黑树:Node。一个node就是put的一个键值对,这样子来实现双端的Map,底层的原理和上面的不一样。这样的好处:可以最大程度的节约存储空间,从而提高效率。


firstKey、lastKey、nextKey等等都有一套自己的实现,处理效率还是蛮高的


备注:使用起来基本同上,因此实例省略


此Map要求key和value必须必须必须都实现了比较器接口


MultiKeyMap:多键Map


MultiKeyMap能够解决我们平时可能遇到的一个痛点。

比如我们Map的key,可能是由多个字段的值联合决定的(有点类似联合索引的意思),这个时候我们一般方案为:自己拼接字符串,然后put进去。


但现在有了MultiKeyMap,我们可以非常优雅的解决这个问题:


     public static void main(String[] args) {
        // MultiKey功能很简单:装载多个key的一个对象
        MultiKey<String> multiKey = new MultiKey<>("a", "b");
        System.out.println(multiKey); //MultiKey[a, b]
        MultiKeyMap<String, String> multiKeyMap = new MultiKeyMap();
        // 多个键对应一个值 两个key:name和NAME
        multiKeyMap.put("name", "NAME", "jianggujin");
        System.out.println(multiKeyMap); //{MultiKey[name, NAME]=jianggujin}
        System.out.println(multiKeyMap.get("name")); //null
        System.out.println(multiKeyMap.get("NAME")); //null
        System.out.println(multiKeyMap.get("name", "NAME")); //jianggujin
        //测试key覆盖
        multiKeyMap.put("name", "shixiang", "cover");
        System.out.println(multiKeyMap); //{MultiKey[name, shixiang]=cover, MultiKey[name, NAME]=jianggujin}
        //这样子  value值才会被覆盖
        multiKeyMap.put("name", "NAME", "cover");
        System.out.println(multiKeyMap); //{MultiKey[name, shixiang]=cover, MultiKey[name, NAME]=cover}
    }

我们可以看到 name+NAME联合确定了一个value值。这样子,我们就可以非常优雅的处理这种情况,并且还不容易犯错。


MultiKeyMap底层采用MultiKey作为普通Map的key,采用HashedMap存储


HashedMap:

源码解释:


* A <code>Map</code> implementation that is a general purpose alternative
 * to <code>HashMap</code>.
 * <p>
 * This implementation improves on the JDK1.4 HashMap by adding the
 * {@link org.apache.commons.collections4.MapIterator MapIterator}
 * functionality and many methods for subclassing.


简单的说就是做了一个HashMap的通用替代品。让也能使用IterableMap的迭代器那样去使用和迭代Map了,没什么多余的可以说明的。



相关文章
|
27天前
|
Java
java8中List对象转另一个List对象
java8中List对象转另一个List对象
37 0
|
1天前
|
存储 安全 Java
[Java基础面试题] Map 接口相关
[Java基础面试题] Map 接口相关
|
2天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
16 3
|
2天前
|
存储 搜索推荐 C++
【C++高阶(二)】熟悉STL中的map和set --了解KV模型和pair结构
【C++高阶(二)】熟悉STL中的map和set --了解KV模型和pair结构
|
6天前
|
Java API Apache
ZooKeeper【基础 03】Java 客户端 Apache Curator 基础 API 使用举例(含源代码)
【4月更文挑战第11天】ZooKeeper【基础 03】Java 客户端 Apache Curator 基础 API 使用举例(含源代码)
24 11
|
9天前
|
消息中间件 存储 Java
深度探索:使用Apache Kafka构建高效Java消息队列处理系统
【4月更文挑战第17天】本文介绍了在Java环境下使用Apache Kafka进行消息队列处理的方法。Kafka是一个分布式流处理平台,采用发布/订阅模型,支持高效的消息生产和消费。文章详细讲解了Kafka的核心概念,包括主题、生产者和消费者,以及消息的存储和消费流程。此外,还展示了Java代码示例,说明如何创建生产者和消费者。最后,讨论了在高并发场景下的优化策略,如分区、消息压缩和批处理。通过理解和应用这些策略,可以构建高性能的消息系统。
|
13天前
|
存储 算法 安全
Java Map:键值对的奇妙之旅
Java Map:键值对的奇妙之旅
41 0
Java Map:键值对的奇妙之旅
|
22天前
|
存储 JavaScript 前端开发
set和map的区别
set和map的区别
29 4
|
24天前
|
Java
Java使用List去重的四中方式
Java使用List去重的四中方式
18 6
|
28天前
Cause: java.sql.SQLIntegrityConstraintViolationException: Column ‘id‘ in field list is ambiguous
Cause: java.sql.SQLIntegrityConstraintViolationException: Column ‘id‘ in field list is ambiguous
17 0

推荐镜像

更多