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 上面的回答 。真是令人惊叹,上面关于这个疑问的讨论,还是十七年前的回答,当时的他们又是人几何年呢。如果也如我一样,那十七年过去了,现在也是不惑之年了。 ↩︎

Map.Entry 接口的更多相关文章

  1. 介绍map.entry接口

    Map是java中的接口,Map.Entry是Map的一个内部接口.java.util.Map.Entry接口主要就是在遍历map的时候用到. Map提供了一些常用方法,如keySet().entry ...

  2. java.util.Map.Entry接口

    java.util.Map.Entry接口主要就是在遍历map的时候用到,给你个例子:package test;import java.util.*;import java.util.Map.Entr ...

  3. Map接口,Map.Entry,hashMap类,TreeMap类,WeakHashMap。

    Collection接口之前接触过,每次保存的对象是一个对象,但是在map中保存的是一对对象,是以key->value形式保存的. 定义: public interface Map<K,V ...

  4. Java集合Map接口与Map.Entry学习

    Java集合Map接口与Map.Entry学习 Map接口不是Collection接口的继承.Map接口用于维护键/值对(key/value pairs).该接口描述了从不重复的键到值的映射. (1) ...

  5. 遍历Map集合:java.util.Map.Entry、KeySet两种方式

    遍历Map集合的两种方式: 1.用KeySet Map.keySet(),返回一个存放所有key的set集合,通过遍历集合,根据key值取出所有的value值. Map<String,Strin ...

  6. Map集合的遍历(利用entry接口的方式)

    核心思想: 调用map集合中的方法entrySet()将集合中的映射关系存放在Set集合中. 迭代Set集合 获取出的Set集合的元素是映射关系对象 通过映射关系对象方法的getKey(),getVa ...

  7. java的Map及Map.Entry解析

    Map<K,V>是以键-值对存储的(key-value), 而Entry<K,V>是Map中的一个接口,Map.Entry<K,V>接口主要用于获取.比较 key和 ...

  8. java Map及Map.Entry详解

    Map是java中的接口,Map.Entry是Map的一个内部接口. Map提供了一些常用方法,如keySet().entrySet()等方法. keySet()方法返回值是Map中key值的集合:e ...

  9. Map.Entry

    Map.Entry Map是java中的接口,Map.Entry是Map的一个内部接口. Map提供了一些常用方法,如keySet().entrySet()等方法,keySet()方法返回值是Map中 ...

随机推荐

  1. 插入Oracle数据库后返回当前主键id

    最近做一个spring版本3.0.4的老项目功能,应用场景要用到插入oracle表后返回主键ID拿来和其他表关联. 用oralce的可以一直用这种处理方式,高兼容低,搜索网上的资料都不能和这个Spri ...

  2. 国内CDH的MAVEN代理

    在编译CDH版本的各个开源软件时,需要从cdh-repo下载对应的jar包,但发现下载速度非常慢,甚至有时候出现下载异常的情况. 下面是国内可用的.速度非常快的一个maven代理仓库,亲测可用: ht ...

  3. 浅谈单例模式及其java实现

    单例模式是23种设计模式中比较简单的一种,在此聊一下单例模式. 1.什么是设计模式? 对于没有接触过设计模式的人来说,一听到设计模式这四个字就觉得这个东西很高深莫测,一下子就对这个东西产生了恐惧感,其 ...

  4. 用JavaScript带你体验V8引擎解析标识符过程

    上一篇讲了字符串的解析过程,这一篇来讲讲标识符(IDENTIFIER)的解析. 先上知识点,标识符的扫描分为快解析和慢解析,一旦出现Ascii值大于128的字符或者转义字符,会进入慢解析,略微影响性能 ...

  5. 富文本编辑器TinyMCE的使用(React Vue)

    富文本编辑器TinyMCE的使用(React Vue) 一,需求与介绍 1.1,需求 编辑新闻等富有个性化的文本 1.2,介绍 TinyMCE是一款易用.且功能强大的所见即所得的富文本编辑器. Tin ...

  6. css常用代码块

    顶部固定导航栏 | css position: fixed; top: 0; left: 0; z-index: 9999; width: 100%; height: 48px; border-top ...

  7. Pandas 库之 DataFrame

    How to use DataFrame ? 简介 创建 DataFrame 查看与筛选数据:行列选取 DataFrame 数据操作:增删改 一.About DataFrame DataFrame 是 ...

  8. C语言编程入门之--第五章C语言基本运算和表达式-part2

    5.1.4 再来一个C库函数getchar吸收回车键 回车键也是一个字符,在使用scanf的时候,输入完毕要按下回车键,这时候回车键也会被输入到stdin流中,会搞乱我们的程序. 注意:stdin是输 ...

  9. Lasso估计论文学习笔记(一)

    最近课程作业让阅读了这篇经典的论文,写篇学习笔记. 主要是对论文前半部分Lasso思想的理解,后面实验以及参数估计部分没有怎么写,中间有错误希望能提醒一下,新手原谅一下. 1.整体思路 作者提出了一种 ...

  10. Visual Studio 2015&2017 key

    Visual Studio 2015 key Key : HMGNV-WCYXV-X7G9W-YCX63-B98R2 Visual Studio Enterprise 2015 Key :HM6NR- ...