The*_*att 13 java java-8 java-stream
我正在查看一些代码并遇到这个方法,它采用HTML Header值(即Content-Disposition = inline; filename = foo.bar)并将其解析为由分号分隔成key = value对的映射.起初它看起来像是使用流进行优化的一个很好的候选者,但是在我实现之后,我无法重用计算的String.indexOf('=')值意味着字符串必须被扫描3次,这是实际上不如原来的最佳.我完全清楚有很多实例,Streams不适合这项工作,但我想知道我是否错过了一些技术,可以让Stream比初始代码更高效/更高效.
/**
* Convert a Header Value String into a Map
*
* @param value The Header Value
* @return The data Map
*/
private static Map<String,String> headerMap (String value) {
int eq;
Map<String,String> map = new HashMap<>();
for(String entry : value.split(";")) {
if((eq = entry.indexOf('=')) != -1) {
map.put(entry.substring(0,eq),entry.substring(eq + 1));
}
}
return map;
return Stream.of(value.split(";")).filter(entry -> entry.indexOf('=') != -1).collect(Collectors.));
} //headerMap
Run Code Online (Sandbox Code Playgroud)
我尝试Streaming it:
/**
* Convert a Header Value String into a Map
*
* @param value The Header Value
* @return The data Map
*/
private static Map<String,String> headerMap (String value) {
return Stream.of(value.split(";")).filter(entry -> entry.indexOf('=') != -1).collect(Collectors.toMap(entry -> entry.substring(0,entry.indexOf('=')),entry -> entry.substring(entry.substring(entry.indexOf('=') + 1))));
} //headerMap
Run Code Online (Sandbox Code Playgroud)
此解决方案'='
仅查找一次:
private static Map<String, String> headerMap(String value) {
return Stream.of(value.split(";"))
.map(s -> s.split("=", 2))
.filter(arr -> arr.length == 2)
.collect(Collectors.toMap(arr -> arr[0], arr -> arr[1]));
}
Run Code Online (Sandbox Code Playgroud)
请注意,这里使用了快速路径String.split
,因此实际上并未创建正则表达式.
请注意,使用Guava,您甚至可以在Java-8之前以非常干净的方式执行此操作:
private static Map<String, String> headerMap(String value) {
return Splitter.on( ';' ).withKeyValueSeparator( '=' ).split( value );
}
Run Code Online (Sandbox Code Playgroud)
一般情况下,我会建议您不要手动解析HTTP标头.那里有很多警告.例如,请参阅如何在Apache HTTP库中实现它.使用库.
我想出了以下代码:
\n\nprivate static Map<String, String> headerMap(String value) {\n return Stream.of(value.split(";"))\n .filter(entry -> entry.indexOf(\'=\') != -1)\n .map(entry -> {\n int i = entry.indexOf(\'=\');\n return new String[] { entry.substring(0, i), entry.substring(i + 1) };\n })\n .collect(Collectors.toMap(array -> array[0], array -> array[1]));\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n它只扫描两次entry
,将键和值存储在大小为 2 的数组中。我不确定它是否会像循环一样高效,for
因为我们正在创建另一个对象来充当持有者。
另一种只扫描entry
一次的解决方案是这样的,尽管我不太发现它:
private static Map<String, String> headerMap(String value) {\n return Stream.of(value.split(";"))\n .map(entry -> {\n int i = entry.indexOf(\'=\');\n if (i == -1) {\n return null;\n }\n return new String[] { entry.substring(0, i), entry.substring(i + 1) };\n })\n .filter(Objects::nonNull)\n .collect(Collectors.toMap(array -> array[0], array -> array[1]));\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n我实现了 JMH 基准测试来测试这一点。以下是基准代码:
\n\n@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)\n@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)\n@BenchmarkMode(Mode.AverageTime)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Fork(3)\n@State(Scope.Benchmark)\npublic class StreamTest {\n\n private static final String VALUE = "Accept=text/plain;"\n + "Accept-Charset=utf-8;"\n + "Accept-Encoding=gzip, deflate;"\n + "Accept-Language=en-US;"\n + "Accept-Datetime=Thu, 31 May 2007 20:35:00 GMT;"\n + "Cache-Control=no-cache;"\n + "Connection=keep-alive;"\n + "Content-Length=348;"\n + "Content-Type=application/x-www-form-urlencoded;"\n + "Date=Tue, 15 Nov 1994 08:12:31 GMT;"\n + "Expect=100-continue;"\n + "Max-Forwards=10;"\n + "Pragma=no-cache";\n\n @Benchmark\n public void loop() {\n int eq;\n Map<String, String> map = new HashMap<>();\n for (String entry : VALUE.split(";")) {\n if ((eq = entry.indexOf(\'=\')) != -1) {\n map.put(entry.substring(0, eq), entry.substring(eq + 1));\n }\n }\n }\n\n @Benchmark\n public void stream1() {\n Stream.of(VALUE.split(";"))\n .filter(entry -> entry.indexOf(\'=\') != -1)\n .map(entry -> {\n int i = entry.indexOf(\'=\');\n return new String[] { entry.substring(0, i), entry.substring(i + 1) };\n })\n .collect(Collectors.toMap(array -> array[0], array -> array[1]));\n }\n\n @Benchmark\n public void stream2() {\n Stream.of(VALUE.split(";"))\n .map(entry -> {\n int i = entry.indexOf(\'=\');\n if (i == -1) {\n return null;\n }\n return new String[] { entry.substring(0, i), entry.substring(i + 1) };\n })\n .filter(Objects::nonNull)\n .collect(Collectors.toMap(array -> array[0], array -> array[1]));\n }\n\n public static void main(String[] args) throws Exception {\n Main.main(args);\n }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n这是结果(代码 i5 3230M CPU @ 2.60 GHz、Windows 10、Oracle JDK 1.8.0_25):
\n\nBenchmark Mode Cnt Score Error Units\nStreamTest.loop avgt 30 1,541 \xc2\xb1 0,038 us/op\nStreamTest.stream1 avgt 30 1,633 \xc2\xb1 0,042 us/op\nStreamTest.stream2 avgt 30 1,604 \xc2\xb1 0,058 us/op\n
Run Code Online (Sandbox Code Playgroud)\n\n这表明流解决方案和 for 循环在性能方面实际上是等效的。
\n 归档时间: |
|
查看次数: |
469 次 |
最近记录: |