如何使用 Streams 将 HashMap 中的数据按排序顺序写入文件

How to write the data from a HashMap into a file in Sorted order with Streams

我可以像这样从 HashMap 输出排序的条目:

public static void sortAverageTime(HashMap<String, Integer> noSortedMap) {
    noSortedMap.entrySet().stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
            .forEach(x -> System.out.println(x + "ms"));
}

但现在我需要将条目写入文件。我这样做:

try {
    File file = new File("newfile.txt");
    if (!file.exists())
        file.createNewFile();
    FileWriter fw = new FileWriter(file, true);
    averageTime.entrySet().stream()
                          .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                          .forEach(x -> fw.write(x + "ms"));
    fw.write("---" + currentDate + "\n");
    fw.close();
}

显示错误

Unhandled exception: java.io.IOException.

如何将排序后的条目从 HashMap 输出到 文件

在将 fw.write(x + "ms"); 写入文件时处理异常,请参见下面的代码。 FileWriter write 函数 thow IO 异常 你没有处理。

try {
            File file = new File("newfile.txt");
            if (!file.exists())
                file.createNewFile();
            FileWriter fw = new FileWriter(file, true);
            noSortedMap.entrySet().stream()
                    .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                    .forEach(x -> {
                        try {
                            fw.write(x + "ms");
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });
            fw.write("---" + new Date() + "\n");
            fw.close();
        }
        catch (Exception e)
        {
            System.out.println("Exception occur emsg= "+w.getMessage());
        }

像写入文件一样放置 IO-operations 不是一个好主意 因为 exception-handling 管道代码完全打败了 lambda 表达式的可读性

在 Java 中引入函数编程的主要原因是提供更好的方法 构建代码,循环总是比 顺序流 .

性能

我建议分两步解决这个问题:首先,准备数据,然后将其写入文件。

准备数据需要:

  • 排序地图内容;
  • 将每个条目转换为 String 并添加 time-unit of "ms";
  • 将排序后的数据收集到列表

第一步可能如下所示:

public static List<String> getSortedData(Map<String, Integer> averageTime) {
    return averageTime.entrySet().stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
            .map(entry -> String.format("%s %d %s", entry.getKey(), entry.getValue(), "ms"))
            .collect(Collectors.toList());
}

正在写入文件(为了更好的性能,FileWriter 被包装成 BufferedWriter

public static void sortAverageTime(Map<String, Integer> averageTime,
                                   String fileName) {
    File file = new File(fileName);
    if (!file.exists())
        file.createNewFile();

    List<String> sortedData = getSortedData(averageTime);
    sortedData.add("---" + LocalDate.now()); // replacement for fw.write("---" + currentDate + "\n")
    try(BufferedWriter writer = new BufferedWriter(new FileWriter(file, true))) {
        for (String next: sortedData) {
            writer.write(next);
            writer.newLine();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

并且使用 Java NIO 第二步可以简化为:

public static void sortAverageTime(Map<String, Integer> averageTime,
                                   String fileName) {
    File file = new File(fileName);
    if (!file.exists())
        file.createNewFile();

    List<String> sortedData = getSortedData(averageTime);
    sortedData.add("---" + LocalDate.now());
    try {
        Files.write(file.toPath(), sortedData, StandardOpenOption.APPEND);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

一些重要说明:

  • Never 关闭 try 块内的资源,如果发生异常,资源将永远不会被释放。为此,可以使用 try with resources(这是首选方式),在 finally 块中显式调用 close()

  • forEach() 操作的用法是 discouraged by the documentation 在有其他方法可以达到相同结果的情况下。所以从流写入文件的方法在所有方面都是不好

    - 它谴责 可读性;

    - 它使您的方法 更少 narrow-focused 并且 更难测试 ;

    -与文档不一致