• Map.Entry 接口


    Map.Entry

    Map 接口下面的 Entry 接口。

    该接口,定义一个键值对实体接口。Map.entrySet 方法返回的 Set 集合中的实体就是实现这个 它。只有一种方法可以获得 Map.Entry 对象的引用,那就是通过集合的迭代器。并且 Map.entry 只在迭代期间有效,更加准确的是意思是,如果在获得迭代器以后,修改了集合,那么 Map.Entry 的行为是未定义的[1]。除非调用 Map.EntrysetValue 设置下修改的值。

    API文档中的这段话,说的让我有点费解。修改集合以后,Map.Entry 的行为是未定义的,LZ 做了实验,发现并没有触发到什么非法,未定义的操作。

       		Map<String, String> stringMap = new HashMap<>(16);
    
            stringMap.put("key1", "value1");
            stringMap.put("key2", "value2");
            stringMap.put("key3", "value3");
            stringMap.put("key4", "value4");
            stringMap.put("key5", "value5");
            stringMap.put("key6", "value6");
    
            Iterator<Map.Entry<String, String>> iterator = stringMap.entrySet().iterator();
    
            Map.Entry<String, String> next = iterator.next();
            stringMap.remove(next.getKey());
            stringMap.put(next.getKey(),"value7");
    

    就如上面的代码所示,在得到 Entry 以后,对集合进行了修改,也没有触发什么非法的状态,抛出什么异常来。这里的未定义,其实是一个很无懈可击的答案,既然是未定义的,那么它们做出的任何行为,都是可以被理解的,所以它没抛出什么异常,那也是对的,抛出异常也是对的,你不应该单方面的任认为它应该怎样怎样,因为它是未定义,不同的实现有不同的反应

    而且这里的合法与非法,是针对 Entry 的值来说,在你获取以后,有人又修改了集合的内容,这时候你获取的 Entry 的内容,也会随之改变,但是你可能不知道集合被修改过,所以这里的合法与非法,是 Entry 是否可以再被信任的问题,所以想要修改值的时候,应该用 entrysetValue() 方法,显示的去改。


    K getKey()

    返回实体对应的 key

    可能抛出的异常 IllegalStateException ,这个异常可以 选择性 的实现。如果实现了,则异常的抛出条件:如果对应的 entry 已经被移除了,则抛出该异常。

    比如,HashMapEntry 就没有实现抛出该异常:

     	static class Node<K,V> implements Map.Entry<K,V> {
          	...
            public final K getKey()        { return key; }
            ...
    	}
    

    EnumMap 则实现了该异常,并且遵守了异常抛出条件:

    	private class Entry implements Map.Entry<K,V> {
               ...
                public K getKey() {
                    checkIndexForEntryUse();
                    return keyUniverse[index];
                }
    			...
    			private void checkIndexForEntryUse() {
                    if (index < 0)
                        throw new IllegalStateException("Entry was removed");
                }
    	}
    

    V getValue()

    返回 entry 实体对应的 value

    如果集合中此 entry 的映射关系已经被移除,即使是通过 iteratorremove 方法,getValue() 方法的返回值也是 未定义。因此,不同的实现,对此方法有不同的做法,HashMap 对其没做什么,正常返回值,即使映射关系被删除了。EnumMap 则抛出异常。

    可能抛出的异常 IllegalStateException ,这个异常可以 选择性 的实现。如果实现了,则异常的抛出条件:如果对应的 entry 已经被移除了,则抛出该异常。


    V setValue(V value)

    替换当前 entryvalue 为传进来的给定的 value ,(map 中对应的 value 也被改变)。如果集合中 entry 的映射关系已经被通过迭代器的 remove() 方法移除,则调用这个方法的行为是 未定义 的。看具体的实现如何操作。同样的 HashMap 对此行为,返回正确的值。EnumMap 则抛出异常。

    返回设置值之前,当前 entry 对应的值。

    可能抛出的异常:

    1. UnsupportedOperationException :如果集合不支持 put 操作,则抛出此异常。
    2. ClassCastException:如果传入的参数,不能转换存储到集合中,则抛出此异常,类型转换异常。
    3. NullPointerException:如果集合不允许存入 null ,其传入的参数确实是 null ,则抛出此异常。
    4. IllegalArgumentException:如果传入的值的某些属性,阻止其存入集合中,则抛出此异常。
    5. IllegalStateException :此异常可选择是否实现。如果 entry 已经被移除了,则抛出此异常。

    boolean equals(Object o)

    将传入的参数对象与当前的 entry 比较,如果传入的对象也是一个 entry 类型,并且它们具有相同的映射关系,则返回 true

    更确切的说,相同的映射关系,应该写成下面的代码: keyvalue 分别相等。

      	(e1.getKey()==null ? e2.getKey()==null : e1.getKey().equals(e2.getKey()))  
      	&&
      	(e1.getValue()==null ? e2.getValue()==null: e1.getValue().equals(e2.getValue()))
    

    这样做以后,可以确保 equals 方法在不同的 Map.Entry 实现之前都能正确的工作。


    int hashCode()

    返回当前 entry 的哈希码。entry 的哈希码计算方法如下:

     	(e.getKey()==null   ? 0 : e.getKey().hashCode())
     	^
        (e.getValue()==null ? 0 : e.getValue().hashCode())
    

    这样做,确保 e1.equals(e2) 时,e1.hashCode()==e2.hashCode() ,当前前提是,这个两个 entryKVhashCode 方法一致 。


    下面几个方法是 1.8 添加进来的。属于静态方法

    comparingByKey()

    public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
                return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> c1.getKey().compareTo(c2.getKey());
            }
    

    返回一个 Comparator ,该比较器对 entrykey进行 自然排序,即按照字典顺序,0-9,a-z

    返回的比较器,实现了 serializable 接口。代码中 (Comparator<Map.Entry<K, V>> & Serializable) 是强转的含义。强转可以这样写,转为二者的结合,但是 & 后面必须是 接口

    可能抛出的异常:NullPointerException ,如果比较的 entrykeynull,则抛出此异常。


    comparingByValue( )

    public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
                return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> c1.getValue().compareTo(c2.getValue());
            }
    

    返回一个 Comparator ,该比较器对 entrykey进行 自然排序

    返回的比较器,实现了 serializable 接口。

    可能抛出的异常:NullPointerException ,如果比较的 entrykeynull,则抛出此异常。


    comparingByKey(Comparator<? super K> cmp)

      public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
                Objects.requireNonNull(cmp);
                return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
            }
    

    返回一个比较器,该比较器对 entrykey 进行比较,根据传入的比较器。如果传入的比较器实现了 serializable 接口,那么返回的比较器也一并实现该接口。


    comparingByValue(Comparator<? super V> cmp)

     public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
                Objects.requireNonNull(cmp);
                return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
            }
    

    返回一个比较器,该比较器对 entryvalue 进行比较,根据传入的比较器。如果传入的比较器实现了 serializable 接口,那么返回的比较器也一并实现该接口。



    1. 可以参考下 codeRanch 上面的回答 。真是令人惊叹,上面关于这个疑问的讨论,还是十七年前的回答,当时的他们又是人几何年呢。如果也如我一样,那十七年过去了,现在也是不惑之年了。 ↩︎

  • 相关阅读:
    Encrypted Handshake Message
    RSAParameters Struct
    What if JWT is stolen?
    What's the difference between JWTs and Bearer Token?
    RSA Algorithm Example
    第18届Jolt大奖结果公布
    Ruby on rails开发从头来(windows)(三十六) 调试技巧
    Ruby on rails开发从头来(四十二) ActiveRecord基础(主键和ID)
    YouTube开放基础技术架构 让用户建自家YouTube
    Ruby on rails开发从头来(四十) ActiveRecord基础(Boolean属性)
  • 原文地址:https://www.cnblogs.com/young-youth/p/11497269.html
Copyright © 2020-2023  润新知