什么是使Java8流生成格式化字符串的高效方法

dot*_*vav 1 java optimization string-formatting java-8 java-stream

上下文:给定一个目录,我想在列表中列出其名称中包含模式的所有文件,按lastModified时间戳排序,并将此列表格式化为Json字符串,我将获取每个文件的名称和时间戳:

[{"name": "somefile.txt", "timestamp": 123456},
{"name": "otherfile.txt", "timestamp": 456789}]
Run Code Online (Sandbox Code Playgroud)

我有以下代码:

private StringBuilder jsonFileTimestamp(File file) {
    return new StringBuilder("{\"name\":\"")
            .append(file.getName())
            .append("\", \"timestamp\":")
            .append(file.lastModified())
            .append("}");
}

public String getJsonString(String path, String pattern, int skip, int limit) throws IOException {

    return Files.list(Paths.get(path))
            .map(Path::toFile)
            .filter(file -> {
                return file.getName().contains(pattern);
            })
            .sorted((f1, f2) -> {
                return Long.compare(f2.lastModified(), f1.lastModified());
            })
            .skip(skip)
            .limit(limit)
            .map(f -> jsonFileTimestamp(f))
            .collect(Collectors.joining(",", "[", "]"));
}
Run Code Online (Sandbox Code Playgroud)

这很好用.我只关心StringBuilder实例化(或字符串连接)的性能.只要文件数量很少就可以了(这是我的情况,所以我很好),但我很好奇:你会建议什么作为优化?我觉得我应该使用reduce正确的累加器和组合器,但我不能让我的大脑围绕它.

谢谢.


UPDATE

我终于进行了以下"优化":

private StringBuilder jsonFileTimestampRefactored(StringBuilder res, File file) {
    return res.append(res.length() == 0 ? "" : ",")
            .append("{\"name\":\"")
            .append(file.getName())
            .append("\", \"timestamp\":")
            .append(file.lastModified())
            .append("}");
}

public String getJsonStringRefactored(String path, String pattern, int skip, int limit) throws IOException {
    StringBuilder sb = Files.list(Paths.get(path))
            .map(Path::toFile)
            .filter(file -> file.getName().contains(pattern))
            .sorted((f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified()))
            .skip(skip)
            .limit(limit)
            .reduce(new StringBuilder(),
                    (StringBuilder res, File file) -> jsonFileTimestampRefactored(res, file),
                    (StringBuilder a, StringBuilder b) -> a.append(a.length() == 0 || b.length() == 0 ? "" : ",").append(b))
            ;
    return new StringBuilder("[").append(sb). append("]").toString();
}
Run Code Online (Sandbox Code Playgroud)

这个版本只创建了2个实例,StringBuilder当旧实例的实例化数量与目录中的文件一样多时.

在我的工作站上,第一个实现需要1289毫秒来完成超过3379个文件,而第二个实现需要1306毫秒.当我期待(非常小的)节省时,第二个实现花费了我多1%的时间.

我不觉得新版本更容易阅读或维护,所以我会保留旧版本.

谢谢大家.

chr*_*ke- 8

字符串格式化是应用程序性能的一个微不足道的部分,几乎不值得优化; 如果分析显示实际的热点,只考虑它.事实上,大多数应用程序使用反射JSON映射器,并且它们的瓶颈在其他地方(通常是I/O).StringBuilder您正在使用的方法是在Java中无需手动操作字符数组的最有效方法,它甚至比我自己(我使用String#format())更远.

为清晰起见,请编写代码.目前的版本很好.

  • +1,唯一可以改进的是使用`StringBuilder(int)`构造函数指定更高的初始容量,因为结果长度可以预测高于16个字符的默认容量.但是,I/O将胜过一切. (3认同)