我正在尝试优化Java 8中的功能操作,而不是与其过程等效的操作,但我遇到了一些严重的性能问题。
情况
我必须从给定枚举的值解析Headers 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代码运行了一个100 k热身+100 k迭代:
FunctionalParsing : 0.040s
ProceduralParsing : 0.010s更新基准#2
我用@Misha代码运行了100 k热身+100 k迭代:
FunctionalParsing : 0.025s
ProceduralParsing : 0.017s发布于 2015-07-15 03:01:51
您的功能代码与原始代码不一样。如果其中一个LogHeader不能匹配一个标头,那么旧代码就会跳过它,而函数代码则会抛出一个NullPointerException。
将原始代码直接转换为流如下所示:
Map<String, List<String>> logHeadersToValue = Arrays.stream(LogHeaders.values())
.collect(
HashMap::new,
(map, logHeader) -> logHeader.getLogKeyVariations().stream()
.filter(httpHeaders::containsKey)
.findAny()
.ifPresent(x -> map.put(logHeader.key, httpHeaders.get(x))),
Map::putAll
);如果您想让它更具表现力,并且易于阅读,请考虑预先计算对其键的每个变体的Map<String,String>。您可以通过这样修改enum来做到这一点:
enum LogHeaders {
SESSION_ID("_sid", "SESSION-ID", "SID"),
CORRELATION_ID("cid", "CORRELATION-ID", "CID");
final String key;
final Map<String, String> variations;
private LogHeaders(final String key, String... variation) {
this.key = key;
variations = Arrays.stream(variation).collect(collectingAndThen(
toMap(x -> x, x -> key),
Collections::unmodifiableMap
));
}
// unmodifiable map of every variation to its key
public final static Map<String, String> variationToKey =
Arrays.stream(LogHeaders.values())
.flatMap(lh -> lh.variations.entrySet().stream())
.collect(collectingAndThen(
toMap(Map.Entry<String, String>::getKey, Map.Entry<String, String>::getValue),
Collections::unmodifiableMap
)); // will throw if 2 keys have the same variation
}如果有重复的变体,这种方法的优点是快速失败。现在,代码变得非常简单:
Map<String, List<String>> logHeadersToValue = LogHeaders.variationToKey.keySet().stream()
.filter(httpHeaders::containsKey)
.collect(toMap(LogHeaders.variationToKey::get, httpHeaders::get));发布于 2015-07-14 16:35:31
我绝对相信你做得不对。很可能你只执行了一次。你不在乎你的程序是工作0.001秒还是0.086秒,对吗?它还是比你眨眼还快。因此,您可能想要多次运行此代码。但是,您似乎只测量了一次时间,并且错误地假设每次连续运行所花费的时间大致相同。在第一次启动期间,代码主要由解释器执行,而它将在稍后进行JIT编译,并将运行得更快。这对于与流相关的代码来说是非常关键的。
至于您的代码,似乎没有必要使用自定义收集器。您可以这样实现它:
final Map<String, List<String>> logHeadersToValue =
EnumSet.allOf(LogHeaders.class)
.stream()
.collect(Collectors.toMap(
LogHeaders::toString,
logHeader -> logHeader.getLogKeyVariations().stream()
.map(httpHeaders::get).filter(Objects::nonNull)
.findFirst().orElse(null)));这个解决方案也可能更快,因为它不会读取一个以上的http头(就像在过程代码中通过break完成的那样)。
https://stackoverflow.com/questions/31411960
复制相似问题