当前位置:网站首页>关于Map做状态映射的问题

关于Map做状态映射的问题

2022-06-22 02:53:00 你家宝宝

1 问题描述

最近工作中,项目里有不少地方需要使用 Map 来做状态映射。

这种状态映射的特点是,一次构建,无限使用,不再修改。

那么问题来了,在 Java 中,创建 Map ,并向里边填充键值对,是一个比较繁琐的重复性工作。

比如将以下的映射关系表达出来:

{
    
    1={
    1=SF, 2=YT, 3=JD}
}

使用 Java 实现需要这样写:

Map<Integer, Map<Integer, String>> maps = new HashMap<>();

Map<Integer, String> map1 = new HashMap<>();
map1.put(1, "SF");
map1.put(2, "YT");
map1.put(3, "JD");

maps.put(1, map1);

那么如果这个过程中,有很多个状态映射,得 new 很多 map,得 put 很多次。这篇文章就来说说这个问题。

2 问题解决

2.1 JAVA 9中 的 Map实现

在 Map 接口中定义了很多个重载的 of 方法,其中2个键值对的方法如下:

static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
    
    return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
}

也就是说,在使用时,可以直接 Map.of(),然后传入参数即可构建你想要的 Map 实例。Java 9 提供了 10对键值对给我们,可以满足大部分需求。

2.2 Hutool中的字典类

具体请参考:

https://www.hutool.cn/docs/#/core/%E8%AF%AD%E8%A8%80%E7%89%B9%E6%80%A7/HashMap%E6%89%A9%E5%B1%95-Dict

2.3 自己造轮子

这里简单写一个demo。

2.3.1 一个demo

package org.feng;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class MapDemo {
    

    private static final MapDemo DEMO = new MapDemo();

    /** * 参数说明:k1,v1,k2,v2,k3,v3... */
    public static Map<Integer, String> intStringMap(Object... objects) {
    
        return DEMO.of(objects);
    }

    /** * 参数说明:k1,v1,k2,v2,k3,v3... */
    public static Map<String, Object> stringObjectMap(Object... objects) {
    
        return DEMO.of(objects);
    }


    @SuppressWarnings("unchecked")
    public final <K, V> Map<K, V> of(Object... object) {
    
        int length = object.length;
        // 长度应该是偶数
        if ((length & 1) != 0) {
    
            throw new IllegalArgumentException("参数个数不正确");
        }

        // size = length / 2
        int size = length >> 1;
        SimpleEntry<K, V>[] entry = new SimpleEntry[size];
        for (int i = 0, j = 0; i < object.length - 1; i += 2) {
    
            entry[j++] = new SimpleEntry<>((K) object[i], (V) object[i + 1]);
        }
        return ofEntry(entry);
    }

    @SafeVarargs
    public final <K, V> Map<K, V> ofEntry(SimpleEntry<K, V>... entries) {
    
        if (entries.length == 0) {
    
            return new HashMap<>(16);
        }

        Map<K, V> instance = new HashMap<>(16);
        for (SimpleEntry<K, V> entry : entries) {
    
            instance.put(entry.key, entry.value);
        }
        return instance;
    }


    private static class SimpleEntry<K, V> implements Map.Entry<K, V> {
    
        private final K key;
        private final V value;

        public SimpleEntry(K key, V value) {
    
            this.key = key;
            this.value = value;
        }

        /** * Returns the key corresponding to this entry. * * @return the key corresponding to this entry * @throws IllegalStateException implementations may, but are not * required to, throw this exception if the entry has been * removed from the backing map. */
        @Override
        public K getKey() {
    
            return this.key;
        }

        /** * Returns the value corresponding to this entry. If the mapping * has been removed from the backing map (by the iterator's * {@code remove} operation), the results of this call are undefined. * * @return the value corresponding to this entry * @throws IllegalStateException implementations may, but are not * required to, throw this exception if the entry has been * removed from the backing map. */
        @Override
        public V getValue() {
    
            return this.value;
        }

        /** * Replaces the value corresponding to this entry with the specified * value (optional operation). (Writes through to the map.) The * behavior of this call is undefined if the mapping has already been * removed from the map (by the iterator's {@code remove} operation). * * @param value new value to be stored in this entry * @return old value corresponding to the entry * @throws UnsupportedOperationException if the {@code put} operation * is not supported by the backing map * @throws ClassCastException if the class of the specified value * prevents it from being stored in the backing map * @throws NullPointerException if the backing map does not permit * null values, and the specified value is null * @throws IllegalArgumentException if some property of this value * prevents it from being stored in the backing map * @throws IllegalStateException implementations may, but are not * required to, throw this exception if the entry has been * removed from the backing map. */
        @Override
        public V setValue(Object value) {
    
            throw new UnsupportedOperationException("SimpleEntry 不允许修改值");
        }

        @Override
        public boolean equals(Object o) {
    
            if (this == o) {
    
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
    
                return false;
            }
            SimpleEntry<?, ?> that = (SimpleEntry<?, ?>) o;
            return Objects.equals(key, that.key) && Objects.equals(value, that.value);
        }

        @Override
        public int hashCode() {
    
            return Objects.hash(key, value);
        }

        @Override
        public String toString() {
    
            return getKey() + "=" + getValue();
        }
    }
}

2.3.2 测试使用

使用main方法调用上述demo。

public static void main(String[] args) {
    
    System.out.println(intStringMap(1, "SF", 2, "YT", 3, "HT"));
    System.out.println(stringObjectMap("1", "SF", "2", "YT", "3", "HT", 1, "HH"));
}

控制台输出结果如下:

{
    1=SF, 2=YT, 3=HT}
{
    1=SF, 1=HH, 2=YT, 3=HT}

2.3.3 注意事项

上述demo中,直接在内部使用 new HashMap 的方式,外部入参使用(k1,v1,k2,v2…)的方式,实际使用的是一个 Object 类型的无限参数。

因此,在构建映射时,对参数具体类型无法确定。需要使用者自己本身清楚这个类用于什么场景下,相当于一种约定吧。

{
    1=SF, 2=YT, 3=HT}
{
    1=SF, 1=HH, 2=YT, 3=HT}

2.3.3 注意事项

上述demo中,直接在内部使用 new HashMap 的方式,外部入参使用(k1,v1,k2,v2…)的方式,实际使用的是一个 Object 类型的无限参数。

因此,在构建映射时,对参数具体类型无法确定。需要使用者自己本身清楚这个类用于什么场景下,相当于一种约定吧。

PS:有更好的想法的话,各位可以留言,我们一起完善。

原网站

版权声明
本文为[你家宝宝]所创,转载请带上原文链接,感谢
https://fengjinsong.blog.csdn.net/article/details/122408921