Java TreeMap

TreeMap 底层使用树结构实现了键值对存储数据,它存储的键值对条目是有序的和可导航的。在本教程中,我们将通过示例了解 Java TreeMap 类及其用法。

在本教程中,我们将通过示例了解 Java TreeMap 类及其用法。

TreeMap 底层使用树结构实现了键值对存储数据,它存储的键值对条目是有序的和可导航的。 TreeMap 实现了实现了 NavigableMap 接口

Java TreeMap 类实现了 Map 接口。

创建 TreeMap

TreeMap 是一个类,我们可以直接使用它的构造方法创建对象。

TreeMap<Key, Value> numbers = new TreeMap<>();

在上面的代码中,我们使用默认的构造方法创建了一个名为 numbersTreeMap 实例。在这种情况下, TreeMap 中的元素自然排序(升序)。

我们也可以在构造方法中传入 Comparator 比较器对象来自定义元素的排序。我们将在本教程的后面部分介绍它。

这里,

  • Key - SortedMap 中键的数据类型
  • Value - SortedMap 中值的数据类型

TreeMap 的方法

TreeMap 类提供许多方法,以便我们能够控制 TreeMap 对象和其中的条目。

将元素插入到 TreeMap

  • put() - 将指定的键值对条目插入到 Map 中
  • putAll() - 将指定 Map 中的所有条目插入到此 Map 中
  • putIfAbsent() - 如果 Map 中不存在指定的键,则将指定的键值对条目插入到 Map 中

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {
    // 一个 TreeMap 对象
    TreeMap<String, Integer> evenNumbers = new TreeMap<>();

    // Using put()
    evenNumbers.put("Two", 2);
    evenNumbers.put("Four", 4);

    // Using putIfAbsent()
    evenNumbers.putIfAbsent("Six", 6);
    System.out.println("evenNumbers: " + evenNumbers);

    // 另一个 TreeMap 对象
    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("One", 1);

    // Using putAll()
    numbers.putAll(evenNumbers);
    System.out.println("numbers: " + numbers);
  }
}

输出

evenNumbers: {Four=4, Six=6, Two=2}
numbers: {Four=4, One=1, Six=6, Two=2}

访问 TreeMap 元素

  1. 使用 entrySet()、keySet() 和 values()

    • entrySet() - 返回所有键值对条目的集合
    • keySet() - 返回 TreeMap 中的所有键的集合
    • values() - 返回 TreeMap 中的所有值的集合

    例如,

    import java.util.TreeMap;
    
    public class Main {
      public static void main(String[] args) {
        TreeMap<String, Integer> numbers = new TreeMap<>();
    
        numbers.put("One", 1);
        numbers.put("Two", 2);
        numbers.put("Three", 3);
        System.out.println("TreeMap: " + numbers);
    
        // Using entrySet()
        System.out.println("Key/Value mappings: " + numbers.entrySet());
    
        // Using keySet()
        System.out.println("Keys: " + numbers.keySet());
    
        // Using values()
        System.out.println("Values: " + numbers.values());
      }
    }
    

    输出

    TreeMap: {One=1, Three=3, Two=2}
    Key/Value mappings: [One=1, Three=3, Two=2]
    Keys: [One, Three, Two]
    Values: [1, 3, 2]
  2. 使用 get() 和 getOrDefault()

    • get() - 返回与指定键关联的值。如果未找到键,则返回 null。
    • getOrDefault() - 返回与指定键关联的值。如果未找到键,则返回指定的默认值。

    例如,

    import java.util.TreeMap;
    
    public class Main {
      public static void main(String[] args) {
    
        TreeMap<String, Integer> numbers = new TreeMap<>();
        numbers.put("One", 1);
        numbers.put("Two", 2);
        numbers.put("Three", 3);
        System.out.println("TreeMap: " + numbers);
    
        // Using get()
        int value1 = numbers.get("Three");
        System.out.println("get(\"Three\"): " + value1);
    
        // Using getOrDefault()
        int value2 = numbers.getOrDefault("Five", 5);
        System.out.println("getOrDefault(\"Five\", 5): " + value2);
      }
    }
    

    输出

    TreeMap: {One=1, Three=3, Two=2}
    get("Three"): 3
    getOrDefault("Five", 5): 5

    在这里,该 getOrDefault() 方法没有找到键 "Five",因此它返回指定的默认值 5

删除 TeeMap 元素

  • remove(key) - 从 TreeMap 中删除并返回与指定键关联的条目
  • remove(key, value) - 仅当指定的键与指定的值相关联时才从 Map 中删除条目, 并返回 true 表示成功,false 表示失败。

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {

    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("One", 1);
    numbers.put("Two", 2);
    numbers.put("Three", 3);
    System.out.println("TreeMap: " + numbers);

    // remove method with single parameter
    int value = numbers.remove("Two");
    System.out.println("Removed value: " + value);

    // remove method with two parameters
    boolean result = numbers.remove("Three", 3);
    System.out.println("Is the entry {Three=3} removed? " + result);

    System.out.println("Updated TreeMap: " + numbers);
  }
}

输出

TreeMap: {One=1, Three=3, Two=2}
Removed value: 2
Is the entry {Three=3} removed? true
Updated TreeMap: {One=1}

替换 TreeMap 元素

  • replace(key, value) - 替换指定键的值为指定的值
  • replace(key, old, new) - 只有当指定的值与指定的旧值匹配的时候,采用新值替换
  • replaceAll(function) - 使用指定的接口函数运算每个条目的结果替换每个条目的值

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {

    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("First", 1);
    numbers.put("Second", 2);
    numbers.put("Third", 3);
    System.out.println("Original TreeMap: " + numbers);

    // Using replace()
    numbers.replace("Second", 22);
    numbers.replace("Third", 3, 33);
    System.out.println("TreeMap using replace: " + numbers);

    // Using replaceAll()
    numbers.replaceAll((key, oldValue) -> oldValue + 2);
    System.out.println("TreeMap using replaceAll: " + numbers);
  }
}

输出

Original TreeMap: {First=1, Second=2, Third=3}
TreeMap using replace: {First=1, Second=22, Third=33}
TreeMap using replaceAll: {First=3, Second=24, Third=35}

在上面的程序中注意语句

numbers.replaceAll((key, oldValue) -> oldValue + 2);

在这里,我们传递了一个 lambda 表达式 “Java lambda 表达式”)作为参数。

replaceAll() 对 Map 中的所有条目 lambda 表达式进行计算,并用返回的值替换条目中的值。

导航方法

TreeMap 类实现了 NavigableMap 接口,它实现了 NavigableMap 接口定义的用于导航元素的方法。

first 和 last 相关的方法

  • firstKey() - 返回 Map 的第一个键
  • firstEntry() - 返回映射的第一个键的键值对条目
  • lastKey() - 返回 Map 的最后一个键
  • lastEntry() - 返回 Map 最后一个键的键值对条目

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {
    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("First", 1);
    numbers.put("Second", 2);
    numbers.put("Third", 3);
    System.out.println("TreeMap: " + numbers);

    // Using the firstKey() method
    String firstKey = numbers.firstKey();
    System.out.println("First Key: " + firstKey);

    // Using the lastKey() method
    String lastKey = numbers.lastKey();
    System.out.println("Last Key: " + lastKey);

    // Using firstEntry() method
    System.out.println("First Entry: " + numbers.firstEntry());

    // Using the lastEntry() method
    System.out.println("Last Entry: " + numbers.lastEntry());
  }
}

输出

TreeMap: {First=1, Second=2, Third=3}
First Key: First
Last Key: Third
First Entry: First=1
Last Entry: Third=3

搜索最接近的匹配值方法

  • higherEntry() - 返回键大于指定键的所有条目中键最小的条目
  • higherKey() - 返回大于指定键的键中最小的键
  • lowerEntry() - 返回键小于指定键的所有条目中键最大的条目
  • lowerKey() - 返回那些小于指定键的键中的最大的键
  • ceilingEntry() - 返回键大于或等于指定键的所有条目中键最小的条目
  • ceilingKey() - 返回大于或等于指定键的键中的最小的键
  • floorEntry() - 返回键小于或等于指定键的所有条目中键最大的条目
  • floorKey() - 返回小于或等于指定键的键中的最大的键

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {
    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("First", 1);
    numbers.put("Second", 5);
    numbers.put("Third", 4);
    numbers.put("Fourth", 6);
    System.out.println("TreeMap: " + numbers);

    // Using higher()
    System.out.println("higherKey(\"Fourth\"): " + numbers.higherKey("Fourth"));
    System.out.println("higherEntry(\"Fourth\"): " + numbers.higherEntry("Fourth"));

    // Using lower()
    System.out.println("\nlowerKey(\"Fourth\"): " + numbers.lowerKey("Fourth"));
    System.out.println("lowerEntry(\"Fourth\"): " + numbers.lowerEntry("Fourth"));

    // Using ceiling()
    System.out.println("\nceilingKey(\"Fourth\"): " + numbers.ceilingKey("Fourth"));
    System.out.println("ceilingEntry(\"Fourth\"): " + numbers.ceilingEntry("Fourth"));

    // Using floor()
    System.out.println("\nfloorKey(\"Fourth\"): " + numbers.floorKey("Fourth"));
    System.out.println("floorEntry(\"Fourth\"): " + numbers.floorEntry("Fourth"));
  }
}

输出

TreeMap: {First=1, Fourth=6, Second=5, Third=4}
higherKey("Fourth"): Second
higherEntry("Fourth"): Second=5

lowerKey("Fourth"): First
lowerEntry("Fourth"): First=1

ceilingKey("Fourth"): Fourth
ceilingEntry("Fourth"): Fourth=6

floorKey("Fourth"): Fourth
floorEntry("Fourth"): Fourth=6

pollFirstEntry() 和 pollLastEntry() 方法

  • pollFirstEntry() - 删除并返回与第一个键关联的条目
  • pollLastEntry() - 删除并返回与最后一个键关联的条目

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {

    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("First", 1);
    numbers.put("Second", 2);
    numbers.put("Third", 3);
    System.out.println("TreeMap: " + numbers);

    // Using the pollFirstEntry() method
    System.out.println("Using pollFirstEntry(): " + numbers.pollFirstEntry());

    // Using the pollLastEntry() method
    System.out.println("Using pollLastEntry(): " + numbers.pollLastEntry());

    System.out.println("Updated TreeMap: " + numbers);
  }
}

输出

TreeMap: {First=1, Second=2, Third=3}
Using pollFirstEntry(): First=1
Using pollLastEntry(): Third=3
Updated TreeMap: {Second=2}

headMap(toKey, inclusive)

headMap(toKey, inclusive) 方法返回由键位于 toKey 所在条目之前的所有条目组成的 NavigableMap 对象。

inclusive 参数如果为 false,该方法返回的 Map 中不包括 toKey 所在的条目;如果为 true,该方法返回的集合中包括 toKey 所在的条目。

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {

    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("First", 1);
    numbers.put("Second", 2);
    numbers.put("Third", 3);
    numbers.put("Fourth", 4);
    System.out.println("TreeMap: " + numbers);

    System.out.println("\nUsing headMap() Method:");
    // Using headMap() with default booleanValue
    System.out.println("Without boolean value: " + numbers.headMap("Fourth"));

    // Using headMap() with specified booleanValue
    System.out.println("With boolean value: " + numbers.headMap("Fourth", true));
  }
}

输出

TreeMap: {First=1, Fourth=4, Second=2, Third=3}

Using headMap() Method:
Without boolean value: {First=1}
With boolean value: {First=1, Fourth=4}

tailMap(fromKey, inclusive)

tailMap(fromKey, inclusive) 方法返回由键位于 fromKey 所在条目之后的所有条目组成的 NavigableMap 对象。

inclusive 参数如果为 false,该方法返回的 Map 中不包括 fromKey 所在的条目;如果为 true,该方法返回的集合中包括 fromKey 所在的条目。

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {

    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("First", 1);
    numbers.put("Second", 2);
    numbers.put("Third", 3);
    numbers.put("Fourth", 4);
    System.out.println("TreeMap: " + numbers);

    System.out.println("\nUsing tailMap() Method:");
    // Using tailMap() with default booleanValue
    System.out.println("Without boolean value: " + numbers.tailMap("Second"));

    // Using tailMap() with specified booleanValue
    System.out.println("With boolean value: " + numbers.tailMap("Second", false));
  }
}

输出

TreeMap: {First=1, Fourth=4, Second=2, Third=3}

Using tailMap() Method:
Without boolean value: {Second=2, Third=3}
With boolean value: {Third=3}

subMap(fromKey, fromInclusive, toKey, toInclusive)

subMap(fromKey, fromInclusive, toKey, toInclusive) 方法返回由键位于 fromKey 条目和 toKey 条目之间的所有条目组成的 NavigableMap 对象。

如果 fromInclusivetrue,则返回的 Map 中包括 fromKey 所在的条目, 为 false 则不包括 fromKey 所在的条目。

如果 toInclusivetrue,则返回的 Map 中包括 toKey 所在的条目, 为 false 则不包括 toKey 所在的条目。

例如,

import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {

    TreeMap<String, Integer> numbers = new TreeMap<>();
    numbers.put("First", 1);
    numbers.put("Second", 2);
    numbers.put("Third", 3);
    numbers.put("Fourth", 4);
    System.out.println("TreeMap: " + numbers);

    System.out.println("\nUsing subMap() Method:");
    // Using subMap() with default booleanValue
    System.out.println("Without boolean value: " + numbers.subMap("Fourth", "Third"));

    // Using subMap() with specified booleanValue
    System.out.println("With boolean value: " + numbers.subMap("Fourth", false, "Third", true));
  }
}

输出

TreeMap: {First=1, Fourth=4, Second=2, Third=3}

Using subMap() Method:
Without boolean value: {Fourth=4, Second=2}
With boolean value: {Second=2, Third=3}

TreeMap 的其他方法

| 方法 | 描述 | | clone() | 创建一个副本 TreeMap | | containsKey() | 搜索 TreeMap 指定的键并返回布尔结果 | | containsValue() | 搜索 TreeMap 指定的值并返回布尔结果 | | size() | 返回大小 TreeMap | | clear() | 从列表中删除所有条目 TreeMap |

TreeMap 比较器

在上面的所有示例中,TreeMap 的元素是根据键自然排序的(按升序)。但是我们也可以自定义键的顺序。

我们可以根据自己的需求创建我们自定义的比较器类。例如,

import java.util.TreeMap;
import java.util.Comparator;

public class Main {
  public static void main(String[] args) {
    // 在构造方法中传入比较器
    TreeMap<String, Integer> numbers = new TreeMap<>(new CustomComparator());

    numbers.put("First", 1);
    numbers.put("Second", 2);
    numbers.put("Third", 3);
    numbers.put("Fourth", 4);
    System.out.println("TreeMap: " + numbers);
  }

  // Creating a comparator class
  public static class CustomComparator implements Comparator<String> {
    @Override
    public int compare(String number1, String number2) {
      // 以自然排序相反的顺序排列
      return number1.compareTo(number2) * -1;
    }
  }
}

输出

TreeMap: {Third=3, Second=2, Fourth=4, First=1}

在上面的例子中,我们创建 TreeMap 对象时,在构造方法中使用自定义比较器对象作为参数。

关于自定义比较器的说明:

  • 自定义比较器需要实现 Comparator 接口
  • compare(a, b) 方法需要传入每次参与比较的 2 个参数,返回值需满足下列条件:
    • 如果 a > b 返回大于 0 的整数
    • 如果 a < b 返回小于 0 的整数
    • 如果 a = b 返回 0

然后我们重写了 compare() 方法以相反的顺序对元素进行排序。