I have an input String and I want to put it into HashMap. String (this is not url params) looks like: source=google&date=2019-01-01&...
public Map<String, String> extract(String source) {
return Arrays.stream(source.split("&"))
.map(s -> s.trim().split("="))
.peek(pairs -> pairs[0] = convert(pairs[0])
.filter(this::isValid)
.collect(Collectors.toMap(
key -> key[0],
value -> value[1],
(val1, val2) -> val2)
);
}
private boolean isValid(String[] strings) {
return strings.length == 2
&& !strings[0].isBlank()
&& !strings[1].isBlank();
}
The result for String above is: [source=google, date=2019-01-01, ..]
But if String has whitespaces like: source = google & date= 2019-01-01
the result will be [ source = google, ...]
.
I want to remove whitespace, so i add:
.map(s -> s.trim().split("="))
.peek(this::removeWhiteSpaces)
private void removeWhiteSpace(String [] strings) {
strings[0] = strings[0].trim();
strings[1] = strings[1].trim();
string[0] = convert(string[0]);
}
It works okay, but now if String cannot be splitted to array with 2 elements, like this: source campaign&date...
it will throw ArrayIndexOutOfBoundException, because string[1]
doesnt exist. So i move filter
above peek
:
.filter(this::isValid)
.peek(pairs -> pairs[0] = convert(pairs[0])
Now String source campaign&date...
will not pass filter, but here is another problem.
Method convert
can return empty String "" and i should filter them. Thats why filter was after peek operator. I can solve it with two filters, like this:
.map(s -> s.trim().split("="))
.filter(strings -> strings.length==2)
.peek(this::removeWhiteSpaces)
.filter(strings -> !strings[0].isBlank() && !strings[1].isBlank())
.collect(..)
But can i do it with one filter? Maybe my stream chain is not good at all?
UPD
convert
method:
private String convert(String string) {
return conversionTable.getOrDefault(string, ""); //map with key/values
}