【小家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了,没什么多余的可以说明的。



相关文章
|
10月前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
4266 113
|
10月前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
563 113
|
10月前
|
JSON Java 关系型数据库
Java更新数据库报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
在Java中,使用mybatis-plus更新实体类对象到mysql,其中一个字段对应数据库中json数据类型,更新时报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
1064 4
Java更新数据库报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
|
10月前
|
存储 算法 Java
Java Set深度解析:为何它能成为“无重复”的代名词?
Java的集合框架中,Set接口以其“无重复”特性著称。本文解析了Set的实现原理,包括HashSet和TreeSet的不同数据结构和算法,以及如何通过示例代码实现最佳实践。选择合适的Set实现类和正确实现自定义对象的hashCode()和equals()方法是关键。
145 4
|
10月前
|
Java
那些与Java Set擦肩而过的重复元素,都经历了什么?
在Java的世界里,Set如同一位浪漫而坚定的恋人,只对独一无二的元素情有独钟。重复元素虽屡遭拒绝,但通过反思和成长,最终变得独特,赢得了Set的认可。示例代码展示了这一过程,揭示了成长与独特性的浪漫故事。
68 4
|
10月前
|
Java 开发者
Java Set:当“重复”遇见它,秒变“独宠”!
在Java编程中,Set接口确保集合中的元素不重复,每个元素都是独一无二的“独宠”。本文介绍了Set的两种常见实现:HashSet和TreeSet。HashSet基于哈希表实现,提供高效的添加、删除和查找操作;TreeSet基于红黑树实现,不仅去重还能对元素进行排序。通过示例代码,展示了这两种集合的具体应用,帮助开发者更好地理解和使用Set。
106 4
|
10月前
|
存储 Java 开发者
Java Set:无序之美,不重复之魅!
在Java的集合框架中,Set接口以其“无序之美”和“不重复之魅”受到开发者青睐。Set不包含重复元素,不保证元素顺序,通过元素的hashCode()和equals()方法实现唯一性。示例代码展示了如何使用HashSet添加和遍历元素,体现了Set的高效性和简洁性。
107 4
|
10月前
|
存储 算法 Java
为什么Java Set如此“挑剔”,连重复元素都容不下?
在Java的集合框架中,Set是一个独特的接口,它严格要求元素不重复,适用于需要唯一性约束的场景。Set通过内部数据结构(如哈希表或红黑树)和算法(如哈希值和equals()方法)实现这一特性,自动过滤重复元素,简化处理逻辑。示例代码展示了Set如何自动忽略重复元素。
89 1
|
10月前
|
存储 算法 Java
Java中的Set,你真的了解它的“无重复”奥秘吗?
在Java的广阔天地里,Set以其独特的“无重复”特性,在众多数据结构中脱颖而出。本文将揭秘Set的“无重复”奥秘,带你领略其魅力。Set通过哈希算法和equals()方法协同工作,确保元素不重复。通过一个简单的案例,我们将展示HashSet如何实现这一特性。
85 1

推荐镜像

更多