I was looking through some code and came across this method that takes an HTML Header value (i.e. Content-Disposition=inline;filename=foo.bar) and parses it into a map separated by the semi-colon's into key=value pairs. At first it looked like a good candidate for optimization using a stream, but after I implemented it, the fact that I can't reuse the computed String.indexOf('=') value means the string must be scanned 3 times, which is actually less optimal than the original. I'm perfectly aware that there are many instances where Streams aren't the right tool for the job, but I was wondering if I had just missed some technique that could allow the Stream to be as performant/more performant than the initial code.
/**
* 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
My attempt at 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
Java 8 Streams API optimises stream processing with the help of short circuiting operations. Short Circuit methods ends the stream processing as soon as their conditions are satisfied.
There are a lot of benefits to using streams in Java, such as the ability to write functions at a more abstract level which can reduce code bugs, compact functions into fewer and more readable lines of code, and the ease they offer for parallelization.
Java provides three predefined stream objects: in, out, and err, defined in the System class of the java.
Introduced in Java 8, the Stream API is used to process collections of objects. A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.
This solution looks for '='
only once:
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]));
}
Note that here the fast-path for String.split
is used, thus regular expression is not actually created.
Note that using Guava you can do this in quite clean way even prior to Java-8:
private static Map<String, String> headerMap(String value) {
return Splitter.on( ';' ).withKeyValueSeparator( '=' ).split( value );
}
In general I would advise you against manual parsing of HTTP headers. There are many caveats there. See, for example, how it's implemented in Apache HTTP library. Use libraries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With