Решение об использовании 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, возвращающий поток после процесса фильтрации, чтобы вы могли работать с ним тоже, если это необходимо?
Ответы
Ответ 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). Кроме того, последним, вероятно, будет проще добавлять более сложные фильтры для продвижения вперед. Однако, если эффективность является основной задачей, я бы пошел с первым.