• MyBatis中的StrictMap类


    Mybatis的Configuration类中使用了大量的Map,但是它没有使用基础的HashMap,而是创建了一个内部类StrictMap

      protected static class StrictMap<V> extends HashMap<String, V>;
    
    • 1

    可以发现该Map的key数据类型被固定了下来,必须是String类型。

      protected static class StrictMap<V> extends HashMap<String, V> {
    
        private static final long serialVersionUID = -4950446264854982944L;
        private final String name;
        private BiFunction<V, V, String> conflictMessageProducer;
    
        public StrictMap(String name, int initialCapacity, float loadFactor) {
          super(initialCapacity, loadFactor);
          this.name = name;
        }
    
        public StrictMap(String name, int initialCapacity) {
          super(initialCapacity);
          this.name = name;
        }
    
        public StrictMap(String name) {
          super();
          this.name = name;
        }
    
        public StrictMap(String name, Map<String, ? extends V> m) {
          super(m);
          this.name = name;
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    相比于HashMap,StrictMap多了一个私有的name属性,它重写了父类的所有初始化方法,要求必须给name赋值。

      protected static class StrictMap<V> extends HashMap<String, V> {
    
        private static final long serialVersionUID = -4950446264854982944L;
        private final String name;
        private BiFunction<V, V, String> conflictMessageProducer;
    
        /**
         * Assign a function for producing a conflict error message when contains value with the same key.
         * 

    * function arguments are 1st is saved value and 2nd is target value. * @param conflictMessageProducer A function for producing a conflict error message * @return a conflict error message * @since 3.5.0 */ public StrictMap<V> conflictMessageProducer(BiFunction<V, V, String> conflictMessageProducer) { this.conflictMessageProducer = conflictMessageProducer; return this; }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    BiFunction是个函数式接口类型,它具有apply这个唯一的抽象方法,apply的目的是将V,V类型的两个参数,转换成String类型。而ConficMessageProducer的作用是生成错误信息,外部可以通过实现apply接口来定义如何返回错误信息。

      protected static class StrictMap<V> extends HashMap<String, V> {
    
        private static final long serialVersionUID = -4950446264854982944L;
        private final String name;
        private BiFunction<V, V, String> conflictMessageProducer;
       
        protected static class Ambiguity {
          private final String subject;
    
          public Ambiguity(String subject) {
            this.subject = subject;
          }
    
          public String getSubject() {
            return subject;
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    StrictMap类中也定义一个Ambiguity类型,它很简单,持有一个String类型的字段,它的作用在后面的put和set方法中有体现。

      protected static class StrictMap<V> extends HashMap<String, V> {
    
        private static final long serialVersionUID = -4950446264854982944L;
        private final String name;
        private BiFunction<V, V, String> conflictMessageProducer;
    
        public StrictMap(String name, int initialCapacity, float loadFactor) {
          super(initialCapacity, loadFactor);
          this.name = name;
        }
    
        public StrictMap(String name, int initialCapacity) {
          super(initialCapacity);
          this.name = name;
        }
    
        public StrictMap(String name) {
          super();
          this.name = name;
        }
    
        public StrictMap(String name, Map<String, ? extends V> m) {
          super(m);
          this.name = name;
        }
        @Override
        @SuppressWarnings("unchecked")
        public V put(String key, V value) {
          if (containsKey(key)) {
            throw new IllegalArgumentException(name + " already contains value for " + key
                + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
          }
          if (key.contains(".")) {
            final String shortKey = getShortName(key);
            if (super.get(shortKey) == null) {
              super.put(shortKey, value);
            } else {
              super.put(shortKey, (V) new Ambiguity(shortKey));
            }
          }
          return super.put(key, value);
        }
    
        private String getShortName(String key) {
          final String[] keyParts = key.split("\\.");
          return keyParts[keyParts.length - 1];
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    先看put方法,相比于HashMap,它在插入一个新的键值对时确实更为严格。只要Map中包含了这个key,立即抛出一个Exception,这里也可以看到conflicMessageProducer生成错误信息。
    如果集合中没有key,但是key中包含了 “ . ” ,比如org.apache.User 那么首先通过私有方法getShortName拿到最后一个" . "对应的部分,根据例子我们拿到的就是User这个key。此时查询字典中是否包含该key,如果不包含就直接插入,如果包含就就插入Ambiguity对象,该对象表示该key存在二义性,相当于一个标识。
    此外,还需要将完整的key插入,也就是org.apache.User插入。

      protected static class StrictMap<V> extends HashMap<String, V> {
    
        private static final long serialVersionUID = -4950446264854982944L;
        private final String name;
        private BiFunction<V, V, String> conflictMessageProducer;
    
       
        @Override
        public V get(Object key) {
          V value = super.get(key);
          if (value == null) {
            throw new IllegalArgumentException(name + " does not contain value for " + key);
          }
          if (value instanceof Ambiguity) {
            throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
                + " (try using the full name including the namespace, or rename one of the entries)");
          }
          return value;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    最后看get方法,它比原生get方法确实也更为严苛,如果集合中不存在要查询的key就报错,还会判断是否是Ambiguity的子类,也就是是否在插入时存在二义性,如果是也会报错

  • 相关阅读:
    恒太照明在北交所上市:募资规模缩水三成,第三季度收入下滑
    JDBC总述
    一文简述:HTTP协议和HTTPS协议
    软考高项(十三)项目资源管理 ★重点集萃★
    Matlab:使用乘法合并分类数组
    MFC C++ 数据结构及相互转化 CString char * char[] byte PCSTR DWORE unsigned
    Spark UI中Shuffle dataSize 和shuffle bytes written 指标区别
    完整版SpringBoot集成Prometheus配置Grafana监控指标包括响应时间分位数TP90,TP80(图+文)
    iOS 关于 UICollectionView常见使用方法
    9.18 Day55---用户和权限
  • 原文地址:https://blog.csdn.net/qq_43152622/article/details/127445840