I've a use-case where I need to parse key-value pairs (separated by =
) and put these key-value pairs in a LinkedHashMap
.
I want to ignore the following type of String
s
- key is empty or contains only spaces
- value is empty or contains only spaces
- those
String
s which don't contain a=
.
Now, I have solved it using imperative style and by using streams also.
The following are the 2 variants:
Solution by iterative style - for
loop and lots of if
public static Map<String, String> getMap1(String[] array) {
Map<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < array.length; i++) {
String currentString = array[i];
int index = currentString.indexOf('=');
// ignoring strings that don't contain '='
if (index == -1) continue;
String key = currentString.substring(0, index).trim();
String value = currentString.substring(index + 1).trim();
// ignoring strings with empty key or value
if (key.length() == 0 || value.length() == 0) continue;
map.put(key, value);
}
return map;
}
Solution that uses Stream
s - pretty clean code
public static Map<String, String> getMap(String[] array) {
return Arrays.stream(array)
.filter(s -> s.indexOf('=') != -1) // ignore strings that don't contain '='
.filter(s -> s.substring(0, s.indexOf('=')).trim().length() != 0) // key should be present
.filter(s -> s.substring(s.indexOf('=') + 1).trim().length() != 0) // value should be present
.collect(Collectors.toMap(
s -> s.substring(0, s.indexOf('=')).trim(),
s -> s.substring(s.indexOf('=') + 1).trim(),
(first, second) -> second,
LinkedHashMap::new));
}
I'm worried here because while using Stream
s, I'm calling the indexOf
method multiple times. (And for big strings, I can end-up recalculating the same thing again and again).
Is there a way I can avoid re-computation done by indexOf
method in such a way that the code is still clean. (I know talking about clean-code is very subjective, but I want don't want to open multiple streams, of loop through the original string-array and subsequently pre-computing the indices of =
and re-using that).
Clubbing multiple filter
s into a single filter again seem to be an option but that would make my predicate pretty ugly.
(This is a result of my idle musing where I wish to learn/improve).
What about this:
String[] array = {"aaa2=asdas","aaa=asdasd"};
LinkedHashMap<String, String> aaa = Arrays.stream(array)
.map(s -> s.split("=", 2))
.filter(s -> s.length == 2) // ignore strings that don't contain '='
.peek(s -> { s[0] = s[0].trim(); })
.peek(s -> { s[1] = s[1].trim(); })
.filter(s -> s[0].length() != 0) // key should be present
.filter(s -> s[1].length() != 0) // value should be present
.collect(Collectors.toMap(
s -> s[0],
s -> s[1],
(first, second) -> second,
LinkedHashMap::new));