I'm a Java 7 person, and have been commanded to never use a for-loop again, with only partial tongue in cheek. I need to take a Map<String, String>, and end up with a string of command-line parameters, as in the output of the following code (ignoring the "streamy" line for the moment):
forLoop: --name5 "value5"--name4 "value4"--name3 "value3"--name2 "{\"x\": \"y\"}"--name1 "value1"
resetAllValues: --name5 "value5"--name4 "value4"--name3 "value3"--name2 "{\"x\": \"y\"}"--name1 "value1"
streamy: --name5 "value5"--name5 "value5"--name4 "value4"--name5 "value5"--name5 "value5"--name4 "value4"--name3 "value3"--name5 "value5"--name5 "value5"--name4 "value4"--name5 "value5"--name5 "value5"--name4 "value4"--name3 "value3"--name2 "{\"x\": \"y\"}"--name5 "value5"--name5 "value5"--name4 "value4"--name5 "value5"--name5 "value5"--name4 "value4"--name3 "value3"--name5 "value5"--name5 "value5"--name4 "value4"--name5 "value5"--name5 "value5"--name4 "value4"--name3 "value3"--name2 "{\"x\": \"y\"}"--name1 "value1"--name5 "value5"--name5 "value5"--name4 "value4"--name5 "value5"--name5 "value5"--name4 "value4"--name3 "value3"--name5 "value5"--name5 "value5"--name4 "value4"--name5 "value5"--name5 "value5"--name4 "value4"--name3 "value3"--name2 "{\"x\": \"y\"}"--name5 "value5"--name5 "value5"--name4 "value4"--name5 "value5"--name5 "value5"--name4 "value4"--name3 "value3"--name5 "value5"--name5 "value5"--name4 "value4"--name5 "value5"--name5 "value5"--name4 "value4"--name3 "value3"--name2 "{\"x\": \"y\"}"--name1 "value1"
The names/keys remain unchanged. The values need to be placed in double quotes, and all existing double quotes need to be escaped (\"). The close-quotes should be followed by a space.
I've done it the pre-java-8 way in forLoop, and partially with streams in resetAllValues, which actually alters each entry. The streamy one is way wrong, as it's repeatedly appending all current output onto the next element...
How can this be done efficiently with streams? And how can it be done in a way that doesn't alter the map entries or use a builder? I'm not seeing it yet.
package working;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class Temp {
public static void main(String[] cmd_lineParams) {
Map<String, String> map = new HashMap<>(5);
map.put("name1", "value1");
map.put("name2", "{\"x\": \"y\"}");
map.put("name3", "value3");
map.put("name4", "value4");
map.put("name5", "value5");
forLoop(map);
resetAllValues(new HashMap<String, String>(map));
streamy(new HashMap<String, String>(map));
}
private static final Matcher matcher = Pattern.compile("\"").matcher("ignored input");
private static final void forLoop(Map<String, String> map) {
StringBuilder builder = new StringBuilder();
for(Map.Entry<String, String> entry : map.entrySet()) {
String value = matcher.reset(entry.getValue()).replaceAll("\\\\\"");
builder.append("--").append(entry.getKey()).append(" \"").append(value).append("\"");
}
System.out.println("forLoop: " + builder.toString());
}
Continued...
private static final void resetAllValues(Map<String, String> map) {
map = map.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey(),
entry -> matcher.reset(entry.getValue()).replaceAll("\\\\\\\"")));
StringBuilder builder = new StringBuilder();
for(Map.Entry<String, String> entry : map.entrySet()) {
builder.append("--").append(entry.getKey()).append(" \"").append(entry.getValue()).append("\"");
}
System.out.println("resetAllValues: " + builder.toString());
}
private static final void streamy(Map<String, String> map) {
StringBuilder builder = new StringBuilder();
map.forEach((k,v) -> builder.append(
builder.append("--").append(k).append(" \"").append(
matcher.reset(v).replaceAll("\\\\\"")).append("\"")));
System.out.println("streamy: " + builder.toString());
}
}
(My nine-year-old says I need to say "difficulty" somewhere in this question. So: difficulty.)