文本内容每行是name;value格式,先上代码

public class ReadTxt {
    public static void main(String[] args) throws Exception {
        var start = System.currentTimeMillis();
        calculate();
        System.err.format("Took %,d ms\n", System.currentTimeMillis() - start);
    }

    private static void calculate() throws Exception {
        var allStats = new BufferedReader(new FileReader("measurements.txt"))
                .lines()
                .parallel()
                .collect(
                        groupingBy(line -> line.substring(0, line.indexOf(';')),
                                summarizingDouble(line ->
                                        parseDouble(line.substring(line.indexOf(';') + 1)))));
        var result = allStats.entrySet().stream().collect(Collectors.toMap(
                Entry::getKey,
                e -> {
                    var stats = e.getValue();
                    return String.format("%.1f/%.1f/%.1f",
                            stats.getMin(), stats.getAverage(), stats.getMax());
                },
                (l, r) -> r,
                TreeMap::new));
        System.out.println(result);
    }
}

解析
这段代码是一个Java方法,其主功能是从一个文本文件中读取数据,按照特定的规则进行分组和统计,然后输出每组数据的最小值、平均值和最大值。下面详细解析这个方法的每个步骤:

  1. 文件读取与流处理:

    var allStats = new BufferedReader(new FileReader("measurements.txt"))
            .lines()
            .parallel()
            .collect(...
    
    • 这段代码首先创建了一个BufferedReader对象来读取名为measurements.txt的文件。
    • lines()方法将这个文件转换为一个流(Stream),其中每个元素代表文件中的一行。
    • parallel()方法的调用使得接下来的流操作可以并行执行,这可能提高处理大文件时的性能。
  2. 数据分组与统计:

    collect(groupingBy(line -> line.substring(0, line.indexOf(';')),
            summarizingDouble(line ->
                    Double.parseDouble(line.substring(line.indexOf(';') + 1)))));
    
    • 这段代码使用collect方法对流中的元素进行收集。
    • groupingBy函数用于根据提供的分类函数对元素进行分组。在这里,分类函数是根据每行数据中;字符前的内容来分组,即假设每行数据的格式为key;value,则按key来分组。
    • summarizingDouble函数用于生成包含统计信息的DoubleSummaryStatistics对象,这里是针对每个分组的value部分(即;字符后的内容),并将其从字符串转换为双精度浮点数(Double)。
  3. 结果处理与格式化输出:

    var result = allStats.entrySet().stream().collect(Collectors.toMap(
            Entry::getKey,
            e -> {
                var stats = e.getValue();
                return String.format("%.1f/%.1f/%.1f",
                        stats.getMin(), stats.getAverage(), stats.getMax());
            },
            (l, r) -> r,
            TreeMap::new));
    System.out.println(result);
    
    • 这段代码处理上一步得到的分组统计结果allStats
    • 使用entrySet().stream()转换分组统计结果为流,然后通过collect方法收集处理后的数据。
    • Collectors.toMap方法用于生成一个映射,其键是分组的键(即每行数据中;前的内容),值是格式化后的字符串,包含每组数据的最小值、平均值和最大值,格式为最小值/平均值/最大值
    • 在冲突的情况下(即两个键相同),选择右边的值((l, r) -> r),尽管在这个场景中不太可能出现键的冲突。
    • 使用TreeMap::new作为收集器的最后一个参数,确保结果是根据键(分组标识)排序的。
  4. 打印结果:

    • System.out.println(result);语句用于打印处理和格式化后的结果。

这个方法从名为measurements.txt的文件中读取数据,按行进行处理,根据每行中;前的内容进行分组,然后计算每个分组中数值(;后的内容)的最小值、平均值和最大值,并按分组键的自然顺序打印出这些统计结果。