从 Java 中的旧地图创建新地图的优雅方式,同时保持元素的排序相同

Elegant way to create a new map from old one in Java, while keeping the sorting of elements the same

让我们考虑以下代码:

//...

public Map<String, Integer> getFruits() throws SomeException {
    QueryResult[] queryResults = queryFruits();
    Map<String, Integer> fruits = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    for (QueryResult qr : queryResults) {
        fruits.put(qr.getField("Name").toString(), (Integer) rec.getField("ArticleNumber"));
    }
    return fruits;
}

//...

public static void main(String args[]) {
    App app = new App();
    Map<String, Integer> originalFruits = app.getFruits();
    System.out.println(originalFruits.keySet());
}

– 执行结果会是

[Apple, banana, cherry, Dragon_Fruit, Papaya ]

之后我调用 getApprovedFuits() 并将 originalFruitswhiteListedFruitNames:

一起传递给它
public Map<String, Integer> getApprovedFruits(Map<String, Integer> fruits, Set<String> whiteListedFruitNames) {
    Map<String, Integer> approvedFruits = new TreeMap<>(fruits);
    approvedFruits.keySet().retainAll(whiteListedFruitNames);
    return approvedFruits;
}

//...

public static void main(String[] args) {
    App app = new App();
    Map<String, Integer> originalFruits = app.getFruits();

    // v

    Set<String> whiteListedFruitNames = new HashSet<>(Arrays.asList("Apple",
                                                                    "banana",
                                                                    "cherry",
                                                                    "Dragon_Fruit",
                                                                    "kiwi",
                                                                    "Pineapple"));

    Map<String, Integer> approvedFruits = getApprovedFruits(originalFruits, whiteListedFruitNames);
    System.out.println(approvedFruits.keySet());

}

– 后者的结果 println() 将如下所示:

[Apple, Dragon_Fruit, banana, cherry]

– 我希望看到这个:

[Apple, banana, cherry, Dragon_Fruit]

我的问题是:如何使地图构造函数 TreeMap<>(fruits) 遵守传递给它的地图的排序顺序?有没有一种优雅的方法可以根据原始地图创建具有相同排序顺序的新地图?

TreeMap 有一个 constructor from a SortedMap that retains the same Comparator (and thus, the ordering). However, since you're passing your TreeMap as a Map, this constructor is not used - instead, the constructor from a Map 被调用,排序丢失。

长话短说 - 更改 getApprovedFruits' 签名以使用 SortedMap,您应该没问题:

public Map<String, Integer> getApprovedFruits
    (SortedMap<String, Integer> fruits, Set<String> whiteListedFruitNames) {

除了@Mureinik 的回答之外还有两个选项:

  1. 使用显式比较器构建新的 TreeMap

    Map<String, Integer> approvedFruits = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    approvedFruits.putAll(fruits);
    
  2. 如果您不打算添加到生成的地图中,您可以使用 LinkedHashMap,它只会保留初始插入顺序:

    Map<String, Integer> approvedFruits = new LinkedHashMap<>(fruits);