Подтвердить что ты не робот

Решение об использовании Stream или Loop

При написании приложений на Java существует много вариантов использования java.util.Collection. Поскольку java.util.stream.Stream был введен с Java 8, я наткнулся на некоторые прецеденты, где трудно решить, что использовать.

Например: Вы собираетесь написать некоторые утилиты-методы.

public static List<?> filterHashToList(int hash, Collection<?> toFilter) {
    return toFilter.stream()
        .filter((Object o) -> hash == o.hashCode())
        .collect(Collectors.toCollection(LinkedList::new));
}

Что можно сказать о написании:

public static List<?> filterHashToList(int hash, Collection<?> toFilter) {
    List<Object> result = new LinkedList<>();

    for(Object o : toFilter) {
        if(hash == o.hashCode()) {
            result.add(o);
        }
    }

    return result;
}

Оба метода приведут к одному и тому же результату. java.util.stream.Stream и java.util.stream.Collector являются интерфейсами, поэтому реализация может также меняться, если я использую пользовательские потоки и коллекторы.

Я думаю, что там есть множество реализаций, используя старую фасонированную петлю.

Итак, можно ли ответить, что использовать, поток или цикл, в случае использования? И если да, нужно ли при необходимости обновлять все реализации?

Или мне даже нужно предоставить оба способа, используя утилиты-методы? Или также я должен предоставить mthed, возвращающий поток после процесса фильтрации, чтобы вы могли работать с ним тоже, если это необходимо?

4b9b3361

Ответ 1

Обратите внимание, что в вашей реализации вы придерживаетесь определенного результирующего типа коллекции LinkedList, который обычно имеет очень низкую производительность по сравнению с ArrayList. Что делать, если пользователь вашего метода хочет использовать полученный список в режиме произвольного доступа? Вероятно, пользователю этого метода нужен массив, потому что он должен быть передан другому методу API, который принимает массив. Иногда пользователю просто нужно знать, сколько объектов с данным хэш-кодом присутствует во входной коллекции, поэтому нет необходимости создавать результирующий список вообще. Способ Java-8 состоит в том, чтобы возвращать потоки из методов, а не в коллекции, и позволяет вызывающему абоненту решить, как его собрать:

public static <T> Stream<T> filterHashToList(int hash, Collection<T> toFilter) {
    return toFilter.stream()
        .filter(o -> hash == o.hashCode());
}

И используйте его:

filterHashToList(42, input).count();

или

filterHashToList(42, input).collect(toCollection(ArrayList::new));

или

filterHashToList(42, input).toArray();

Таким образом, метод становится очень простым, поэтому вы, вероятно, вообще не нуждаетесь в нем, но если вы хотите сделать более сложную фильтрацию/преобразование, это нормально.

Итак, если вы не хотите изменять API и все еще возвращаете LinkedList, нет необходимости изменять реализацию. Но если вы хотите воспользоваться преимуществами использования Stream API, лучше изменить тип возврата на Stream.

Ответ 2

В отсутствие опубликованного ответа я приведу Брайан Гетц, который перекликается с моим чувством, и я подозреваю многих других.

Там нет ничего волшебного ни о потоках, ни в цикле. Вы должны написать код, который является наиболее читаемым, понятным и поддерживаемым. Любой из них является приемлемым.

Ответ 3

Я думаю, что это во многом зависит от ожидаемого размера коллекции и практического применения программы. Первый немного более эффективен, но я считаю, что он менее читабельный, и все еще есть системы, которые работают на Java 7 (т.е. Google App Engine). Кроме того, последним, вероятно, будет проще добавлять более сложные фильтры для продвижения вперед. Однако, если эффективность является основной задачей, я бы пошел с первым.