【发布时间】:2014-08-06 16:27:59
【问题描述】:
上下文:给定一个目录,我想列出其中名称中包含模式的所有文件,按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% 的时间。
我不觉得新版本更容易阅读或维护,所以我会保留旧版本。
谢谢大家。
【问题讨论】:
-
您的意思可能是
return name == null ? false,即排除空名称。虽然我不确定在什么情况下会发生这种情况...... -
在 lambdas 中,您可以删除 { return 和关闭 }
-
您可以将
.sorted((f1, f2) -> { return Long.compare(f2.lastModified(), f1.lastModified()); })替换为.sorted(Comparator.comparingLong(File::lastModified)) -
感谢 cmets。我已经删除了
name上的测试,因为它是我的生产代码的遗留问题,我忘记为这个问题清理了。 -
您应该使用像 Jackson 或 Gson 这样的适当库来创建 JSON。如果文件名中包含无效字符,您将获得无效的 JSON。使用名称和时间戳字段创建 POJO,映射到该对象,收集到列表,然后将列表转换为带有实际 JSON 库的 JSON 数组。
标签: java optimization java-8 string-formatting java-stream