map遍历的几种方式_Java Map常用的几种用法。

Java Map常用的几种用法。

通常,Map是由一组键值对组成的数据结构,每个键只能在映射中出现一次。这篇文章总结了有关如何使用Java Map及其实现的类的前9个常见问题解答。为了简单起见,我将在示例中使用泛型。因此,我将只写Map而不是具体的Map。但是,您始终可以假设K和V都是可比较的,这意味着K extends ComparableV extends Comparable

0.将Map转换为列表

在Java中,Map接口提供了三个集合视图:键集,值集和键值集。可以使用构造函数或addAll()方法将它们全部转换为List。以下代码段显示了如何从地图构造ArrayList

// key list
List keyList = new ArrayList(map.keySet());
// value list
List valueList = new ArrayList(map.values());
// key-value list
List entryList = new ArrayList(map.entrySet());

1.遍历Map

遍历每对键值是遍历地图的最基本操作。在Java中,这样的对存储在名为Map.Entry的映射条目中。Map.entrySet()返回键值集,因此遍历Map每个条目的最有效方法是

for(Entry entry: map.entrySet()) {
  // get key
  K key = entry.getKey();
  // get value
  V value = entry.getValue();
}

也可以使用Iterator,尤其是在JDK 1.5之前

for(Entry entry: map.entrySet()) {
  // get key
  K key = entry.getKey();
  // get value
  V value = entry.getValue();
}
Iterator itr = map.entrySet().iterator();
while(itr.hasNext()) {
  Entry entry = itr.next();
  // get key
  K key = entry.getKey();
  // get value
  V value = entry.getValue();
}

2.以Map的key排序

KeyMap进行排序是另一种常见的操作。一种方法是将Map.Entry放入列表中,并使用对值进行排序的比较器对其进行排序。

List list = new ArrayList(map.entrySet());
Collections.sort(list, new Comparator() {
 
  @Override
  public int compare(Entry e1, Entry e2) {
    return e1.getKey().compareTo(e2.getKey());
  }
 
});

另一种方法是使用SortedMap,它进一步提供了其键的总排序。因此,所有密钥必须实现Comparable或被比较器接受。

一个实现类的SortedMap的是TreeMap的。它的构造函数可以接受比较器。以下代码显示了如何将普通Map转换为排序Map。

SortedMap sortedMap = new TreeMap(new Comparator() {
 
  @Override
  public int compare(K k1, K k2) {
    return k1.compareTo(k2);
  }
 
});
sortedMap.putAll(map);

3.根据values对Map排序

Map放入列表并对其进行排序也适用于这种情况,但是我们需要比较Entry.getValue()。下面的代码与以前几乎相同。

List list = new ArrayList(map.entrySet());
Collections.sort(list, new Comparator() {
 
  @Override
  public int compare(Entry e1, Entry e2) {
    return e1.getValue().compareTo(e2.getValue());
  }
 
});

我们仍然可以对此问题使用排序映射,但前提是值也必须唯一。在这种情况下,您可以将key = value对反转为value = key。这个解决方案有很强的局限性,因此我不推荐这样做。

初始化静态/不可变Map

当您希望Map保持不变时,将其复制到不可变Map中是一种好习惯。这种防御性编程技术不仅可以帮助您创建安全使用的线程,而且还可以创建线程安全的Map

要初始化静态/不可变Map,我们可以使用静态初始化器(如下所示)。这段代码的问题在于,尽管Map被声明为static final,但我们仍然可以在初始化后像上操作它Test.map.put(3,"three")``;。因此,它并不是真正不变的。要使用静态初始化程序创建不可变的Map,我们需要一个额外的匿名类,并在初始化的最后一步将其复制到不可修改的Map中。请参阅第二段代码。然后,如果运行,将抛出UnsupportedOperationExceptionTest.map.put(3,"three");`。

public class Test {
 
  private static final Map map;
  static {
    map = new HashMap();
    map.put(1, "one");
    map.put(2, "two");
  }
}
public class Test {
 
  private static final Map map;
  static {
    Map aMap = new HashMap();
    aMap.put(1, "one");
    aMap.put(2, "two");
    map = Collections.unmodifiableMap(aMap);
  }
}

Guava库还支持引入静态和不可变集合的不同方法。要了解有关Guava不可变集合实用程序的好处的更多信息,请参见《Guava用户指南》中介绍的不可变集合。

5. HashMap,TreeMap和Hashtable之间的区别

Java中有三个主要的Map接口实现:HashMapTreeMapHashtable。最重要的区别包括:

  • 1.迭代的顺序。 HashMapHashtable不保证Map的顺序;特别是,它们不能保证顺序会随着时间的推移保持恒定。但是TreeMap将根据键的“自然顺序”或由比较器迭代整个条目。

  • 2.键值取值。 HashMap允许使用null键和null值(仅允许使用一个null键,因为不允许两个键相同)。哈希表不允许使用空键或空值。如果TreeMap使用自然顺序或其比较器不允许使用null键,则将引发异常。

  • 3.线程安全。Hashtable是线程安全的,其它的都不是。因此,“如果不需要线程安全的实现,建议使用HashMap代替Hashtable。”

比较完整的比较是

HashMap哈希表树状图
迭代顺序没有没有
空键值yes-yesno-nono-yes
线程安全没有是的没有
时间复杂度O(1)O(1)O(log n)
实现方式水桶水桶红黑树

6.具有反向查找的Map,value找key

有时,我们需要一组键-键对,这意味着映射的值和键(一对一映射)都是唯一的。该约束使得能够创建Map的“反向查找”。因此,我们可以通过键的值查找键。这种数据结构称为双向映射,不幸的是JDK不支持。

Apache Common CollectionsGuava都提供了双向地图的实现,分别称为BidiMapBiMap。两者都强制要求键和值之间存在1:1关系的限制。

7.Map的浅表副本

Java的大多数映射实现(如果不是全部)都提供了另一个映射副本的构造函数。但是复制过程不同步。这意味着当一个线程复制Map时,另一线程可以在结构上进行修改。为了[防止意外的非同步副本,应该使用Collections。提前进行syncedMap()

Map copiedMap = Collections.synchronizedMap(map);

浅表复制的另一种有趣方式是使用clone()方法。但是,Java收集框架的设计者Josh Bloch甚至不建议这样做。

我经常在具体的类上提供公共克隆方法,因为人们期望这样做。...可克隆性被破坏很遗憾,但是它确实发生了。...可克隆是一个薄弱环节,我认为人们应该意识到它的局限性。

因此,我什至不会告诉您如何使用clone()方法复制地图。

8.创建一个空的Map

如果Map是不可变的,请使用

map = Collections.emptyMap();

否则,请使用任何实现。例如

map =  new  HashMap ();

6a019499f55db3d0df804d9986e14caa.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值