Java中Map的几种排序方式

一.Map的常用方法

在Java中,Map 接口是一个非常重要的数据结构,用于存储键值对。Map 的每个键都是唯一的,并且每个键映射到一个特定的值。Java 提供了几种 Map 实现,包括 HashMapLinkedHashMapTreeMap 等。下面是一些在使用 Map 时常用的方法和实践。

基本操作

put(K key, V value)
Map<String, Integer> map = new HashMap<>();
map.put("apple", 3);
map.put("banana", 5);
get(Object key)

返回指定键所映射的值,如果此映射不包含该键的映射关系,则返回 null

int count = map.get("apple");  // 返回 3
remove(Object key)

如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。

map.remove("apple");
containsKey(Object key)

如果此映射包含指定键的映射关系,则返回 true

boolean hasApple = map.containsKey("apple");  // 返回 true 或 false
containsValue(Object value)

如果此映射将一个或多个键映射到指定值,则返回 true

boolean containsThree = map.containsValue(3);
keySet()

返回此映射中包含的键的 Set 视图。

Set<String> keys = map.keySet();  // 获取所有键
values()

返回此映射中包含的值的 Collection 视图。

Collection<Integer> values = map.values();  // 获取所有值
entrySet()

返回此映射中包含的映射关系的 Set 视图。

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String key = entry.getKey();
    Integer value = entry.getValue();
    System.out.println(key + " -> " + value);
}

更新和计算

putIfAbsent(K key, V value)

如果指定的键尚未关联值(或映射到 null),将其与给定值关联并返回 null,否则返回当前值。

map.putIfAbsent("cherry", 10);
replace(K key, V value)

只有当目标键已经存在于 Map 中时,才将目标键的值设置为提供的值。

map.replace("banana", 6);  // 将 "banana" 的值更新为 6
computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)

如果指定键的值不存在或为 null,尝试使用给定的映射函数计算其值,并将其插入到 Map 中。

map.computeIfAbsent("orange", k -> 7);
computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)

如果指定键的值存在且不为 null,则尝试重新计算其值。

map.computeIfPresent("banana", (k, v) -> v + 1);
compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)

无论键是否存在,都尝试计算其值。

map.compute("banana", (k, v) -> (v == null) ? 42 : v + 1);

批量操作

forEach(BiConsumer<? super K, ? super V> action)

Map 中的每个键值对执行给定的操作。

map.forEach((key, value) -> System.out.println(key + " has " + value + " items"));
clear()

清除 Map 中的所有键值对。

map.clear();

二.TreeMap, HashMap, LinkedHashMap

1. HashMap

特点
  • 无序HashMap不保证随着时间的推移,Map中的元素顺序是恒定的。
  • 键值约束:允许将null作为键和值。
  • 性能:为基本操作如getput提供常数时间的性能(O(1)),这种性能假设哈希函数将元素适当分布在buckets中。

2. LinkedHashMap

特点
  • 有序LinkedHashMap维护元素插入的顺序或者最近最少使用(LRU)顺序。
  • 键值约束:允许null键和null值。
  • 性能:略低于HashMap的性能,因为维护了元素的插入顺序,但对于创建有序的缓存非常有用。
独有方法
  • removeEldestEntry(Map.Entry<K,V> eldest):可以被覆盖,以实现在新元素添加到map时自动移除最老的元素。通常用于基于LRU策略的缓存。

3. TreeMap

特点
  • 排序TreeMap按照自然顺序或者构造时指定的Comparator对键进行排序。
  • 键值约束:不允许null键(如果使用自然排序或者自定义的Comparator不允许null),但允许null值。
  • 性能:提供对键的有序遍历,基本操作(如获取和放置)的性能为对数时间(O(log n))。
独有方法
  • firstKey(), lastKey():获取排序后的第一个和最后一个键。
  • headMap(K toKey), tailMap(K fromKey), subMap(K fromKey, K toKey):返回键的范围视图

比较三种Map

性能
  • HashMap通常提供最快的查找性能,因为它的操作几乎是常数时间的。
  • LinkedHashMap的性能略低于HashMap,因为它维护了元素的插入顺序。
  • TreeMap的性能通常是O(log n),适用于需要有序访问的场景。
用途
  • HashMap是最通用的Map,适用于需要快速访问的情况,不关心元素的顺序。
  • LinkedHashMap适用于需要保持插入顺序的场景,如缓存和记忆最近插入/访问的元素。
  • TreeMap适用于需要按自然顺序或自定义顺序访问键的情况,如范围搜索和排序显示。
资源消耗
  • HashMapLinkedHashMap的内存消耗类似,但LinkedHashMap因为额外维护了链表结构而稍高。
  • TreeMap通常消耗更多的内存,因为它基于红黑树结构。

三.排序方法

1. 按键排序

TreeMap 在内部就是按照键的自然顺序(或者根据构造函数中提供的比较器)进行排序的。

Map<String, Integer> unsortedMap = new HashMap<>();
unsortedMap.put("one", 1);
unsortedMap.put("three", 3);
unsortedMap.put("two", 2);

SortedMap<String, Integer> sortedMap = new TreeMap<>(unsortedMap);

2. 按值排序

如果要按照值对 Map 进行排序,你需要额外的步骤,因为 Map 的值没有内建的排序机制。一种常见的做法是使用辅助的列表来排序,然后再将结果放入 LinkedHashMap(这会保留元素的插入顺序)。

Map<String, Integer> unsortedMap = new HashMap<>();
unsortedMap.put("one", 1);
unsortedMap.put("three", 3);
unsortedMap.put("two", 2);

// 使用流对值进行排序
LinkedHashMap<String, Integer> sortedByValue = unsortedMap.entrySet()
    .stream()
    .sorted(Map.Entry.comparingByValue())
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue,
        (e1, e2) -> e1,
        LinkedHashMap::new
    ));

3. 自定义排序

比如根据多个字段或条件排序,可以自定义比较器(Comparator)

Map<String, Integer> unsortedMap = new HashMap<>();
unsortedMap.put("one", 1);
unsortedMap.put("three", 3);
unsortedMap.put("two", 2);

// 自定义比较器来进行排序
LinkedHashMap<String, Integer> customSortedMap = unsortedMap.entrySet()
    .stream()
    .sorted((entry1, entry2) -> {
        // 根据值降序排列,如果值相等,则按键升序排列
        int valueComparison = entry2.getValue().compareTo(entry1.getValue());
        return (valueComparison != 0) ? valueComparison : entry1.getKey().compareTo(entry2.getKey());
    })
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue,
        (e1, e2) -> e1,
        LinkedHashMap::new
    ));
  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值