Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java流优化商机_Java_Java 8_Java Stream - Fatal编程技术网

使用Java流优化商机

使用Java流优化商机,java,java-8,java-stream,Java,Java 8,Java Stream,我浏览了一些代码,发现了这个方法,它接受一个HTML标题值(即Content Disposition=inline;filename=foo.bar),并将其解析为一个由分号into key=value对分隔的映射。起初,它看起来像是使用流进行优化的一个很好的候选者,但在我实现它之后,我无法重用计算的字符串。indexOf('=')值意味着必须扫描字符串3次,这实际上不如原始字符串优化。我非常清楚,在很多情况下,流不是适合此工作的工具,但我想知道我是否错过了一些技术,这些技术可以使流的性能与初始

我浏览了一些代码,发现了这个方法,它接受一个HTML标题值(即Content Disposition=inline;filename=foo.bar),并将其解析为一个由分号into key=value对分隔的映射。起初,它看起来像是使用流进行优化的一个很好的候选者,但在我实现它之后,我无法重用计算的字符串。indexOf('=')值意味着必须扫描字符串3次,这实际上不如原始字符串优化。我非常清楚,在很多情况下,流不是适合此工作的工具,但我想知道我是否错过了一些技术,这些技术可以使流的性能与初始代码相同/更高

  /**
   * 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
/**
*将标题值字符串转换为映射
*
*@param value标题值
*@返回数据地图
*/
私有静态映射头映射(字符串值){
国际均衡器;
Map Map=newhashmap();
for(字符串条目:value.split(;)){
if((eq=entry.indexOf('='))!=-1){
map.put(entry.substring(0,eq),entry.substring(eq+1));
}
}
返回图;
返回Stream.of(value.split(“;”).filter(条目->条目.indexOf('=')!=-1.collect(收集器));
}//头映射
我尝试将其流式传输:

  /**
   * 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
/**
*将标题值字符串转换为映射
*
*@param value标题值
*@返回数据地图
*/
私有静态映射头映射(字符串值){
返回Stream.of(value.split(“;”).filter(entry->entry.indexOf('=')!=-1).collect(Collectors.toMap(entry->entry.substring(0,entry.indexOf('=')),entry->entry.substring(entry.indexOf('=')+1));
}//头映射

我想出了以下代码:

private static Map<String, String> headerMap(String value) {
    return Stream.of(value.split(";"))
                .filter(entry -> entry.indexOf('=') != -1)
                .map(entry -> {
                    int i = entry.indexOf('=');
                    return new String[] { entry.substring(0, i), entry.substring(i + 1) };
                })
                .collect(Collectors.toMap(array -> array[0], array -> array[1]));
}
我实现了一个JMH基准测试来测试这一点。以下是基准代码:

@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(3)
@State(Scope.Benchmark)
public class StreamTest {

    private static final String VALUE = "Accept=text/plain;"
        + "Accept-Charset=utf-8;"
        + "Accept-Encoding=gzip, deflate;"
        + "Accept-Language=en-US;"
        + "Accept-Datetime=Thu, 31 May 2007 20:35:00 GMT;"
        + "Cache-Control=no-cache;"
        + "Connection=keep-alive;"
        + "Content-Length=348;"
        + "Content-Type=application/x-www-form-urlencoded;"
        + "Date=Tue, 15 Nov 1994 08:12:31 GMT;"
        + "Expect=100-continue;"
        + "Max-Forwards=10;"
        + "Pragma=no-cache";

    @Benchmark
    public void loop() {
        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));
            }
        }
    }

    @Benchmark
    public void stream1() {
        Stream.of(VALUE.split(";"))
        .filter(entry -> entry.indexOf('=') != -1)
        .map(entry -> {
            int i = entry.indexOf('=');
            return new String[] { entry.substring(0, i), entry.substring(i + 1) };
        })
        .collect(Collectors.toMap(array -> array[0], array -> array[1]));
    }

    @Benchmark
    public void stream2() {
        Stream.of(VALUE.split(";"))
        .map(entry -> {
            int i = entry.indexOf('=');
            if (i == -1) {
                return null;
            }
            return new String[] { entry.substring(0, i), entry.substring(i + 1) };
        })
        .filter(Objects::nonNull)
        .collect(Collectors.toMap(array -> array[0], array -> array[1]));
    }

    public static void main(String[] args) throws Exception {
         Main.main(args);
    }

}

这表明streams解决方案和for循环在性能方面实际上是等效的。

此解决方案只查找一次
'='

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

一般来说,我建议您不要手动解析HTTP头。这里有很多警告。例如,请参见ApacheHTTP库中的内容。使用库。

一般来说,流可以使代码更短,并允许您更轻松地并行化,但一般来说,您不应该期望流可以使代码更快。同意,但使用流可能会降低代码速度,只是为了节省一点代码空间,不建议这样做。在大多数情况下,您可以通过精心设计的流链获得速度(或至少不会失去速度)。我希望在我的尝试中错过了一些更为精通的人能够指出的东西。事实上,我不确定我是否接受这两种说法中的任何一种——我非常乐意接受一些减速来换取代码可读性的提高,但我不确定流是否能够带来速度的提高(除了简化并行化)。溪流只是一个图书馆;JIT对它们进行了很好的优化,但如果它们优于经过良好调优的命令式代码,我至少会有点惊讶。而且您的原始解析代码似乎太脆弱,缺少许多关键案例。这是针对此类标题的,但在其中添加额外的对象创建可能会抵消删除字符串扫描的好处。尤其是由于HTTP头字符串的大小通常相当短;我想这样会更好。然后并行处理每个元素。哇,做得很好。“我从来没用过那个工具,我一定要试试看。”克里斯登内特,在这种情况下,拆分器有什么优势?我看不出有什么好处。你可以提前读取整个字符串,并在不需要的时候生成一个字符串数组。很好!我必须将它添加到@Tunaki的JMH基准测试中,并对它们进行正面测试。我实际上是将此作为优化机会的示例,而不是解析HTTP头的正确方法。
Benchmark           Mode  Cnt  Score   Error  Units
StreamTest.loop     avgt   30  1,541 ± 0,038  us/op
StreamTest.stream1  avgt   30  1,633 ± 0,042  us/op
StreamTest.stream2  avgt   30  1,604 ± 0,058  us/op
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]));
}
private static Map<String, String> headerMap(String value) {
    return Splitter.on( ';' ).withKeyValueSeparator( '=' ).split( value );
}