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

时间:2014-08-06 16:28:00

标签: java optimization java-8 string-formatting java-stream

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

[{"name": "somefile.txt", "timestamp": 123456},
{"name": "otherfile.txt", "timestamp": 456789}]

我有以下代码:

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(",", "[", "]"));
}

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

感谢。


更新

我终于接受了以下“优化”:

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();
}

这个版本只创建了2个StringBuilder个实例,而旧版本实例的实例化数量与目录中的文件数量相同。

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

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

谢谢大家。

1 个答案:

答案 0 :(得分:8)

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

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