java - 使用Comparator.comparing(HashMap::get)作为比较器时发生意外行为

标签 java sorting hashmap java-stream method-reference

https://java-programming.mooc.fi/part-10/2-interface-comparable上进行“文学”练习时,当我尝试对HashMap中的键/值对进行排序而不将任何内容复制到TreeMap时,发现了一个非常奇怪的行为。我应该通过制作Book类并将它们添加到List中来添加书籍。但是我想尝试不创建新类,因此选择了HashMap。我的代码如下:

public class MainProgram {

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);

    Map<String, Integer> bookshelf = new HashMap<>();
    while (true) {


        System.out.println("Input the name of the book, empty stops: ");
        String bookName = scanner.nextLine();
        if (bookName.equals("")) {
            break;
        }
        System.out.println("Input the age recommendation: ");
        int age = Integer.valueOf(scanner.nextLine());

        bookshelf.put(bookName, age);
    }

    System.out.println(bookshelf.size() + " book" + (bookshelf.size() > 1 ? "s" : "") + " in total.");

    System.out.println("Books:");

    bookshelf.keySet().stream().sorted(Comparator.comparing(bookshelf::get)).forEach((key) -> System.out.println(key + " (recommended for " + bookshelf.get(key) + " year-olds or older)"));
}

}

我使用.sorted(Comparator.comparing(bookshelf::get))是按照建议的年龄对它们进行排序的想法,这种方法行得通。

但是,存在一种出乎意料的行为,即当书名是单个字符(“A”,“b”)时,该程序还会按字母顺序对键进行排序,就好像我做了类似Comparator.comparing(bookshelf::get).thenComparing(/*keys in keyset*/)的比较器一样,但有时也会像aAbB
AA bb give unsorted results
AAA bbb give semi-sorted results in one or two buckets
AAAA bbbb give semi- or completely sorted results
AAAAA bbbbb and onward give unsorted results.

enter image description here

任何人都可以在编译器级别解释这里发生的事情,或者以某种方式让我理解这一点吗?

最佳答案

bookshelf.keySet().stream().sorted(Comparator.comparing(bookshelf::get))

从示例中的以上代码片段,我们可以看到您正在尝试按其各自的值对bookshelf的键进行排序。

问题在于,两个书名可能会映射到相同的年龄推荐。由于您只有一个Comparator,而且HashMap没有指定一致的顺序,因此对于相同的输入,您有机会以不同的结果结束。

为了改善这一点,您可以使用thenComparing处理遇到重复值映射的情况:
bookshelf.entrySet()
         .stream()
         .sorted(Map.Entry.<String, Integer>comparingByValue().thenComparing(Map.Entry.comparingByKey()))
         .forEach(entry -> System.out.println(entry.getKey() + " (recommended for " + entry.getValue() + " year-olds or older)"));

关于java - 使用Comparator.comparing(HashMap::get)作为比较器时发生意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62200170/

相关文章:

计算 h 指数

python:遍历按键排序的字典

java - HashMap 没有给出预期的输出

JAVA如何迭代map的map中的值

java - 如何通过 Java 访问 XBMC JSON 接口(interface)?

java - 在 Google Android 中以编程方式连接到 WiFi?

java - SpringFramework 和 DbUnit 集成测试类未找到 AnnotationBeanConfigurerAspect Java

java - 排序和重新排列(不同的)数组

java - 单键多个账户映射

java - ExecutorService FixThreadPool 作为共享参数不并行运行