How to concatenate all map key-values into a string, using streams, with replacements made on each value?
I guess since you said difficulty, I'll have to answer this! :)
map.entrySet().stream().map((entry) -> //stream each entry, map it to string value
"--" + entry.getKey() + " \"" + entry.getValue().replaceAll("\"", "\\\\\"") + "\"")
.collect(Collectors.joining(" ")); //and 'collect' or put them together by joining
I personally don't like using streams because it gets ugly pretty quick, but its useful for simpler loops. (join all values with some character for example) With this however you can easily parallelize it by using parallelStream()
instead of stream()
If you wanted the values in some sort of order so its not so random (as it will be with HashMap
) you can do a sort before map:
.stream().sort((e1, e2) -> e1.getValue().compareTo(e2.getValue()))
.map(...)...
Just remember that those are Map.Entry
objects.
UPDATE: Tagir Valeev's answer below is better, as it shows the best practice instead of just making it work. It also remedies the initial gripe I had with streams + lambdas couple years back when I wrote this answer (getting too ugly).
Always try to decompose your complex problem into simple and independent parts. Here (both for stream and non-stream solution) it's better to put the escaping code into the separate method:
static String quoteValue(String value) {
return "\"" + value.replaceAll("\"", "\\\\\"") + "\"";
}
This way you have a separate piece of code with clear semantic which can be reused and tested separately. For example, in future you may need to escape a back-slash symbol as well, because currently you may have problems decoding the string which originally had the mix of back-slashes and quotes. If would be much easier to debug this problem if you have a separate quoteValue
method (this way you should not create the test map, just test string).
After that the stream solution becomes less confusing:
map.entrySet().stream().map(entry ->
"--" + entry.getKey() + " "+ quoteValue(entry.getValue()))
.collect(joining(" "));
You can go further and add one more method to format the whole entry as well:
static String formatEntry(String key, String value) {
return "--" + key + " " + quoteValue(value);
}
map.entrySet().stream().map(e -> formatEntry(e.getKey(), e.getValue()))
.collect(joining(" "));