在Java8中按值比较返回奇怪的结果

在Java8中按值比较返回奇怪的结果,java,dictionary,java-8,Java,Dictionary,Java 8,我正在尝试根据值对地图进行排序 但是我在下面的节目中看到了一些奇怪的行为 public class CompareByValueMain { public static void main(String[] args) { Map<String,Integer> itemIDToTimeMap = new HashMap<String,Integer>(); itemIDToTimeMap.put("Baggage", 3);

我正在尝试根据值对地图进行排序

但是我在下面的节目中看到了一些奇怪的行为

public class CompareByValueMain {

    public static void main(String[] args) {
        Map<String,Integer> itemIDToTimeMap = new HashMap<String,Integer>();

        itemIDToTimeMap.put("Baggage", 3);
        itemIDToTimeMap.put("Handbag", 16);
        itemIDToTimeMap.put("Closed Footwear", 4);
        itemIDToTimeMap.put("Shirt", 25);

        Set<String> itemIDs = itemIDToTimeMap.entrySet().stream()
                .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
                .map(Map.Entry::getKey)
                .collect(Collectors.toSet());

        System.out.println(itemIDs);
    }
}
public类CompareByValueMain{
公共静态void main(字符串[]args){
Map itemIDToTimeMap=newhashmap();
itemIDToTimeMap.put(“行李”,3);
itemIDToTimeMap.put(“手提包”,16);
itemIDToTimeMap.put(“封闭式鞋类”,4);
itemIDToTimeMap.put(“衬衫”,25);
Set itemIDs=itemIDToTimeMap.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.map(map.Entry::getKey)
.collect(收集器.toSet());
System.out.println(itemIDs);
}
}
结果证明输出是正确的

[衬衫、手提包、封闭式鞋类、行李]

但是当我从行李更改为行李 它给出以下输出

[衬衫,,手提包,封闭式鞋类]


理想情况下,应根据地图中的值进行排序,而不考虑键值。但不确定如果在此处更改了键,它为什么会更改。

您正在将结果收集到
集中。并非所有
都设置了
s担保订单。

因此,排序工作正常,但之后它存储在一个容器中,而不必考虑字符串的顺序

排序完成后,使用类似于
List
的容器存储数据。这将保证您的物品的顺序

public class CompareByValueMain {

    public static void main(String[] args) {
        Map<String,Integer> itemIDToTimeMap = new HashMap<String,Integer>();

        itemIDToTimeMap.put("Bag", 3); // already changed to "Bag" to demonstrate the working code
        itemIDToTimeMap.put("Handbag", 16);
        itemIDToTimeMap.put("Closed Footwear", 4);
        itemIDToTimeMap.put("Shirt", 25);

        List<String> itemIDs = // use List<> instead of Set<>
                itemIDToTimeMap.entrySet().stream()
                .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
                .map(Map.Entry::getKey)
                .collect(Collectors.toList()); // use .toList() instead of .toSet()

        System.out.println(itemIDs);
    }
}
哪些产出:

List:
b
a

Set:
a
b
默认的
toSet()
收集器返回一个不保留插入顺序的
HashSet

参见8u60中的实现(注意,这是一个内部细节):

公共静态收集器toSet(){
返回新的CollectorImpl((供应商)HashSet::new,Set::add,
(左,右)->{left.addAll(右);返回left;},
(未订购);;
}
您可以使用
.collect(Collectors.toCollection(LinkedHashSet::new))以提供特定的实现(保留插入顺序)。

问题在于:

.collect(Collectors.toSet());
因为
Collectors.toSet()
返回未排序的
HashSet
(因为在大多数情况下,我们实际上不需要在集合中排序,但其
的速度包含
HashSet
提供的方法)

如果要保留插入顺序,请使用
LinkedHashSet

.collect(Collectors.toCollection(LinkedHashSet::new));


或者,根据您希望如何使用此结果,可以使用列表来代替?

@slartidan对我来说,问题在于单词
shuffle
。对我来说,这意味着顺序是随机的,而你的最后一段代码表明它不是。一个更好的方法是
收集器.toSet
不保持原始顺序。
.collect(Collectors.toSet());
.collect(Collectors.toCollection(LinkedHashSet::new));