Правильное использование потоков в Java - PullRequest
2 голосов
/ 15 апреля 2019

У меня есть сценарий использования, когда мне нужно проанализировать пары ключ-значение (разделенные =) и поместить эти пары ключ-значение в LinkedHashMap.

Я хочу игнорировать следующий тип ключа String s

  • пуст или содержит только пробелы
  • значение пусто или содержит только пробелы
  • те String с, которые не содержат =.

Теперь я решил это с помощью императивного стиля и с помощью потоков.

Ниже приведены 2 варианта:

Решение с помощью итерационного стиля - for цикл и множество 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;
}

Решение, которое использует Stream s - довольно чистый код

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

}

Я волнуюсь, потому что при использовании Stream s,Я вызываю метод indexOf несколько раз.(И для больших строк я могу в конечном итоге пересчитывать одно и то же снова и снова).

Есть ли способ, которым я могу избежать повторного вычисления, сделанного методом indexOf в такомспособ, которым код все еще чист.(Я знаю, что говорить о чистом коде очень субъективно, но я не хочу открывать несколько потоков, проходить через исходный строковый массив, а затем предварительно вычислять индексы = и повторно использовать это).

Объединение нескольких filter s в один фильтр снова кажется вариантом, но это сделало бы мой предикат довольно уродливым.

(Это результат моих бесполезных размышлений, когда я хочуузнать / улучшить).

Ответы [ 2 ]

3 голосов
/ 15 апреля 2019

Что по этому поводу:

 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));
0 голосов
/ 15 апреля 2019

Я бы использовал split вместо indexOf и StringUtils, чтобы проверить, что ваши ключи и значения не пусты.

 public static Map<String, String> getMap(String[] array) {
        return Arrays.stream(array)
                .filter(s -> s.contains("="))
                .map(s -> s.split("="))
                .filter(s -> s.length == 2 && isNotBlank(s[0]) && isNotBlank(s[1]))
                .collect(Collectors.toMap(
                        s -> s[0].trim(),
                        s -> s[1].trim()));
    }
...