【发布时间】:2015-07-14 16:12:54
【问题描述】:
我正在尝试优化 Java 8 中的函数操作,与它的等效程序相比,但我遇到了一些严重的性能问题。
情况
我必须从给定枚举的值中解析 HTTP 标头 String, List<String>,该枚举将 HeaderName 映射到许多可能的变体 String, Set<String>。
示例
鉴于以下 HttpHeaders :
public static final Map<String, List<String>> httpHeaders = new HashMap<>();
httpHeaders.put("Content-Type", Arrays.asList("application/json", "text/x-json"));
httpHeaders.put("SID", Arrays.asList("ABC123"));
httpHeaders.put("CORRELATION-ID", Arrays.asList("ZYX666"));
还有我的自定义枚举:
LogHeaders
protected final String key;
protected final Set<String> variation;
SESSION_ID("_sid", Arrays.asList("SESSION-ID", "SID"));
CORRELATION_ID("cid", Arrays.asList("CORRELATION-ID", "CID")),
private LogHeaders(final String logKey, final List<String> logKeyVariations) {
this.logKey = logKey;
this.logKeyVariations = new HashSet<>(logKeyVariations);
}
@Override
public String toString() {
return this.logKey;
}
结果应该是“LogHeaders.key”的映射,其中包含来自 HttpHeaders 的相应变体的值集。对于给定的标头,只有一种变化是可能的:
// {LogHeaders.key : HttpHeaderValue>
{
_sid=[ABC123],
_cid=[ZYX666]
}
程序代码
final Map<String, List<String>> logHeadersToValue = new HashMap<>();
for (final LogHeaders header : LogHeaders.values()) {
for (final String variation : header.getLogKeyVariations()) {
final List<String> headerValue = httpHeaders.get(variation);
if (headerValue != null) {
logHeadersToValue.put(header.logKey, headerValue);
break;
}
}
}
功能代码
final Map<String, List<String>> logHeadersToValue =
EnumSet.allOf(LogHeaders.class)
.stream()
.collect(Collectors.toMap(
LogHeaders::toString,
logHeader -> logHeader.getLogKeyVariations().stream()
.map(variation -> httpHeaders.get(variation)).filter(Objects::nonNull)
.collect(singletonCollector())));
public static <T> Collector<T, ?, T> singletonCollector() {
return Collectors.collectingAndThen(Collectors.toList(), list -> {
if (list.size() < 1) {
return null;
}
return list.get(0);
});
}
当前基准
FunctionalParsing : 0.086s
ProceduralParsing : 0.001s
您知道如何优化我的功能部分吗?
谢谢
更新基准
我使用@Tagir Valeev 代码运行了 100k 预热 + 100k 迭代:
FunctionalParsing : 0.040s
ProceduralParsing : 0.010s
更新基准 #2
我使用@Misha 代码运行了 100k 热身 + 100k 迭代:
FunctionalParsing : 0.025s
ProceduralParsing : 0.017s
【问题讨论】:
-
第一个问题显然是,你是如何衡量性能的,第二个问题是这些集合大致有多大?
-
当涉及到任何新的闪亮功能 f 时,您似乎是一个典型错误的受害者:使用 f 是为了使用 f 而你就是 f;你的旧代码工作得很好,既然 f 显然没有好处,为什么还要尝试使用它呢?
-
没有人告诉过函数式代码更快。
-
忘记性能——“功能”代码完全不可读
-
我也愿意接受任何“可读性”建议。我使用了 Junit 测试输出。准备好后,我将使用 JMH 基准测试我的问题。
标签: java functional-programming java-8 procedural-programming