Proper usage of Streams in Java

Lavish Kothari :

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 Strings

  • key is empty or contains only spaces
  • value is empty or contains only spaces
  • those Strings 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 Streams - 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 Streams, 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 filters 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).

Nonika :

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));

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=134858&siteId=1