Рефакторинг метода с использованием потокового API - PullRequest
8 голосов
/ 26 марта 2019

В настоящее время мне приказывают считать все файлы .sql, которые находятся на некоторых серверах.Вручную решить эту очень базовую задачу не вариант, вместо этого я написал некоторый код, использующий SimpleFileVisitor<Path> и сохраняющий все найденные sql-файлы вместе с его родительским путем в Map<Path, List<Path>>.

Теперь я хочу получить общее количество найденных файлов sql независимо от их расположения.У меня получилось работать с расширенным циклом for (почти классическим способом):

public int getTotalAmountOfSqlFiles(Map<Path, List<Path>> sqlFilesInDirectories) {
    int totalAmount = 0;

    for (Path directory : sqlFilesInDirectories.keySet()) {
        List<Path> sqlFiles = sqlFilesInDirectories.get(directory);
        totalAmount += sqlFiles.size();
    }

    return totalAmount;
}

Вопрос теперь, как я могу сделать то же самое с помощью потокового API?

Я не смог заставить работать скомпилированный код, который явно не делает неправильно.
Следующая строка выглядит как хорошая идея для меня, но не длякомпилятор, к сожалению.

totalAmount = sqlFilesInDirectories.entrySet().stream().map(List::size).sum();

Компилятор говорит

Невозможно определить тип аргумента (ов) для <R> map(Function<? super T,? extends R>

Кто-нибудь знает, что яя делаю что-то не так (и, может быть, предоставил какое-нибудь образованное потоковое API с использованием решения)?

Ответы [ 4 ]

13 голосов
/ 26 марта 2019

Не уверен, почему люди вовлекают keySet здесь, когда необходимая сумма имеет только размер списка, содержащийся в значениях.Суммируйте размер всех значений.

return sqlFilesInDirectories.values().stream().mapToInt(List::size).sum();

И даже версия цикла for должна быть просто такой:

for (List<Path> list : sqlFilesInDirectories.values()) {
    totalAmount += list.size();
}

Поскольку перебор набора ключей, а затем получение значения из карты недействительно требуется и не будет лучшей производительности.

4 голосов
/ 26 марта 2019

Это потому, что в потоке вы принимаете целые записи вместо значений. Это должно сделать это:

totalAmount = sqlFilesInDirectories.values().stream().map(List::size).sum();
3 голосов
/ 26 марта 2019

Другие ответы предоставляют кратчайший способ суммирования всех записей, но если вам нужно количество скриптов на Path, вы можете использовать следующее:

Map<Path, Integer> amountOfFilesForPath =
        files.entrySet().stream().collect(Collectors.groupingBy(Map.Entry::getKey,
        Collectors.summingInt(value -> value.getValue().size())));

И вы также можете получить общую стоимость:

int sum = amountOfFilesForPath.values().stream().mapToInt(Integer::intValue).sum();
1 голос
/ 26 марта 2019

Попробуйте

int totalAmount = sqlFilesInDirectories.keySet().stream().map(sqlFilesInDirectories::get).mapToInt(List::size).sum();
...