序言

平时开发中,用的比较多的可能就是hashMap、LinkedHashMap、ConcurrentHashMap,但其实还有好多可以用的Map。

MultiKeyMap

官方网址:MultiKeyMap (Apache Commons Collections 4.4 API)

MultiKeyMap继承自抽象类AbstractMapDecorator,AbstractMapDecorator抽象类又继承自AbstractIterableMap抽象类,Java中所有类的父类是Object。

看MultiKeyMap类的实现可以发现它是将多个key(重载的put方法中有2个键、3个键、4个键、5个键以及键数组)通过hash运算得到hash值,然后再用hash值和数据长度减1做与运算得到的索引值。

这样做的好处就是可以通过2~5个关键字组合映射到对应的值,下面是一个简单的demo。

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.map.MultiKeyMap;

public class MultiKeyMapTest {
    /**
     * 如果考虑并发则使用volatile保证线程可见性,但不能保证原子性
     */
    private static final MultiKeyMap<Object, ValueObject> ID_MAP = new MultiKeyMap<>();

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    private static class ValueObject {
        @JsonProperty("name")
        private String name;
        private int age;
    }

    public static void main(String[] args) {
        ID_MAP.put("key1", "key2", ValueObject.builder().name("test1").age(13).build());
        ID_MAP.put("key1", "key2", "key3", ValueObject.builder().name("test2").build());
        ID_MAP.put(new MultiKey<>("key1", "key2", "key3", "key4", "key5"), ValueObject.builder().name("test3").build());
        System.out.println(ID_MAP.get("key1", "key2"));
        System.out.println(ID_MAP.get("key1", "key2", "key3"));
        System.out.println(ID_MAP.get("key1", "key2", "key3", "key4", "key5"));
    }
}

MultiValueMap

上面有多个key对应一个value,这里有一个key对应多个value,即MultiValueMap,

官方网站:MultiValueMap (Apache Commons Collections 4.4 API)

使用也比较简单,

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;

public class MultiMapTest {
    public static void main(String[] args) {
        MultiMap giftMap = new MultiValueMap();
        giftMap.put("gift", "flower");
        giftMap.put("gift", "ring");
        System.out.println(giftMap.get("gift"));    //[flower, ring]
    }
}

DualHashBidiMap

官方网址:DualHashBidiMap (Apache Commons Collections 4.4 API)

比如我们在做接口调用时,可能调用下层接口时可能存在某个字段有关联但表征不同。我们可能需要建一个中间转换的枚举或者存一个有映射关系的Map,然后通过中间转换器去做映射。

打个比方,使用枚举建立中间关系。

import lombok.AllArgsConstructor;

@AllArgsConstructor
public enum MappingEnum {
    APPLE("apple", "fruit"),
    KNIFE("knife", "tool");
    private String primaryKey;
    private String secondaryKey;

    /**
     * 通过值获得对应的键
     *
     * @param value 值
     * @return 键
     */
    public String getKeyByValue(String value) {
        for (MappingEnum enums : MappingEnum.values()) {
            if (enums.secondaryKey.equalsIgnoreCase(value)) {
                return enums.primaryKey;
            }
        }
        return null;
    }

    /**
     * 通过键获得值
     *
     * @param key 键
     * @return 值
     */
    public String getValueByKey(String key) {
        for (MappingEnum enums : MappingEnum.values()) {
            if (enums.primaryKey.equalsIgnoreCase(key)) {
                return enums.secondaryKey;
            }
        }
        return null;
    }
}

那么使用DualHashBidiMap也能达到从key中获取value,从value中获取key的效果,

DualHashBidiMap里放了一个容量为2的Map数组,第一个Map放正向映射Map,第二个Map放反向映射Map。

import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.DualHashBidiMap;

public class DualHashBidiMapTest {
    public static void main(String[] args) {
        BidiMap bidiMap = new DualHashBidiMap();
        bidiMap.put("apple", "fruit");
        bidiMap.put("knife", "tool");
        System.out.println("Key-Value: Value = " + bidiMap.get("apple"));   //fruit
        System.out.println("Value-Key: Key = " + bidiMap.getKey("fruit"));  //apple
        System.out.println("Key-Value: Value = " + bidiMap.get("knife"));   //tool
        System.out.println("Key-Value: Key = " + bidiMap.getKey("tool"));   //knife
    }
}

LRUMap

LRU(Least Recently Used,最近最少使用)属于缓存淘汰机制中的一种,前面也有介绍,

传送门:缓存淘汰算法_四问四不知的博客-CSDN博客

官方网站:LRUMap (Apache Commons Collections 4.4 API)

  • put 操作:如果当前map大小大于等于Map的最大容量,且加入的元素不在Map集合中,则从缓存中删除最近最少使用的元素。
  • get 操作:如果获取的元素在Map集合中,则先删除元素,再将元素到map中。

使用示例如下,

import java.util.Collections;
import java.util.Map;

public class LRUMapTest {
    public static void main(String[] args) {
        LRUMap<String, String> lruMap = new LRUMap<>(3);
        Map<String, String> map = Collections.synchronizedMap(lruMap);
        map.put("cache1", "MD5_21841259921");
        map.put("cache2", "MD5_48102837152");
        map.put("cache3", "MD5_66666639123");
        map.get("cache1");
        map.get("cache2");
        map.put("cache5", "MD5_97817293405");
        System.out.println(map);//{cache1=MD5_21841259921, cache2=MD5_48102837152, cache5=MD5_97817293405}
    }
}

总结

上面介绍了几种不常用的Map,一方面可以对一些不常用的类或对象加深印象,另一方面也可以学习不同的使用方法,好让自己在写代码时有更多的选择。

对于不同或相同数据类型的映射关系我们可以用Map保存返回,有时可能也会需要使用那种轻量级的对象结构把不同数据类型的对象放在一起从方法中返回出去。javafx的工具包中就提供了Pair类可以实现,下面是一个简单例子,

import javafx.util.Pair;

public class PairTest {
    public static void main(String[] args) {
        Pair<String, Boolean> pair = new Pair<>("test", true);
        System.out.println("key : " + pair.getKey());
        System.out.println("value : " + pair.getValue());
    }
}

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐