Я задаюсь вопросом, почему Iterable
интерфейс не обеспечивают stream()
и parallelStream()
методы. Рассмотрим следующий класс:
public class Hand implements Iterable<Card> {
private final List<Card> list = new ArrayList<>();
private final int capacity;
//...
@Override
public Iterator<Card> iterator() {
return list.iterator();
}
}
Это реализация руки, так как вы можете иметь карты в руке во время игры в карточную игру.
По сути, это обертка List<Card>
, обеспечивает максимальную емкость и предлагает некоторые другие полезные функции. Это лучше, как реализовать его непосредственно как List<Card>
.
Теперь для удобства я подумал, что было бы неплохо реализовать Iterable<Card>
такую возможность, чтобы вы могли использовать расширенные циклы for, если хотите зациклить его. (Мой Hand
класс также предоставляет get(int index)
метод, поэтому, на Iterable<Card>
мой взгляд, это оправдано.)
Iterable
Интерфейс обеспечивает следующее (левый из JavaDoc):
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
Теперь вы можете получить поток с:
Stream<Hand> stream = StreamSupport.stream(hand.spliterator(), false);
Итак, на настоящий вопрос:
- Почему
Iterable<T>
не предусмотрены методы по умолчанию, которые реализуют,stream()
иparallelStream()
я не вижу ничего, что сделало бы это невозможным или нежелательным?
Похожий вопрос, который я обнаружил, заключается в следующем: почему Stream <T> не реализует Iterable <T>?
Что довольно странно, предлагая сделать это несколько иначе.
источник
break;
сделать итерацию? (Хорошо,Stream.findFirst()
возможно, это решение, но оно не может удовлетворить все потребности ...)Ответы:
Это не было упущением; в июне 2013 года состоялось подробное обсуждение списка ЭГ.
Окончательное обсуждение группы экспертов происходит от этой темы .
Хотя это казалось «очевидным» (даже для группы экспертов на начальном этапе), что,
stream()
казалось, имело смыслIterable
, сам факт, которыйIterable
носил столь общий характер, стал проблемой, потому что очевидная подпись:не всегда было то, что вы хотели. Некоторые вещи, которые были
Iterable<Integer>
бы, скорее всего, имеют свой потоковый метод, возвращающийIntStream
, например. Но если поместить этотstream()
метод высоко в иерархии, это будет невозможно. Поэтому вместо того , мы сделали это очень легко сделатьStream
изIterable
, обеспечиваяspliterator()
метод. Реализацияstream()
вCollection
это просто:Любой клиент может получить желаемый поток с помощью
Iterable
:В итоге мы пришли
stream()
к выводу, что добавление вIterable
будет ошибкой.источник
Iterable<Integer>
(я думаю, вы говорите?) Хотели бы вернутьIntStream
. Будет ли итерируемый, а неPrimitiveIterator.OfInt
? Или вы имеете в виду другой вариант использования?Stream.of(Iterable)
, которая, по крайней мере, сделала бы метод разумно доступным для обнаружения, читая документацию по API - как тот, кто никогда не работал с внутренними компонентами потоков, я бы никогда не стал даже смотрел наStreamSupport
, который описан в документации, обеспечивая «низкоуровневые операции», которые « в основном для библиотеки писателей».Я провел расследование в нескольких лямбда-рассылках проекта, и, думаю, нашел несколько интересных обсуждений.
Я не нашел удовлетворительного объяснения до сих пор. Прочитав все это, я пришел к выводу, что это просто упущение. Но вы можете видеть здесь, что это обсуждалось несколько раз за годы разработки API.
Специалисты по Lambda Libs Spec
Я нашел обсуждение этого вопроса в списке рассылки Lambda Libs Spec Experts :
Под Iterable / Iterator.stream () Сэм Пуллара сказал:
И тогда Брайан Гетц ответил :
И позже
Предыдущие обсуждения в списке рассылки Lambda
Возможно, это не тот ответ, который вы ищете, но в списке рассылки Project Lambda это было кратко обсуждено. Возможно, это помогает стимулировать более широкую дискуссию на эту тему.
По словам Брайана Гетца в разделе « Потоки из Итерибла» :
Противоречие?
Хотя, похоже, что обсуждение основано на изменениях, которые Группа экспертов внесла в первоначальный дизайн Streams, который изначально был основан на итераторах.
Тем не менее, интересно отметить, что в интерфейсе, подобном Collection, метод stream определяется как:
Это может быть тот же код, который используется в интерфейсе Iterable.
Вот почему я сказал, что этот ответ, вероятно, не является удовлетворительным, но все же интересным для обсуждения.
Свидетельство Рефакторинга
Продолжая анализ в списке рассылки, похоже, что метод splitIterator изначально был в интерфейсе Collection, и в какой-то момент в 2013 году они переместили его в Iterable.
Вытяните splitIterator из коллекции в итерируемую .
Заключение / Теории?
Тогда есть вероятность, что отсутствие метода в Iterable является просто упущением, поскольку похоже, что они должны были также переместить потоковый метод, когда они переместили splitIterator из Collection в Iterable.
Если есть другие причины, они не очевидны. У кого-то еще есть другие теории?
источник
spliterator()
изIterable
, то все вопросы там фиксируются, и вы можете тривиальным реализоватьstream()
иparallelStream()
..Если вы знаете размер, который вы можете использовать,
java.util.Collection
который обеспечиваетstream()
метод:А потом:
Я столкнулся с той же проблемой и был удивлен, что моя
Iterable
реализация может быть легко расширена доAbstractCollection
реализации, просто добавивsize()
метод (к счастью, у меня был размер коллекции :-)Вы также должны рассмотреть возможность переопределения
Spliterator<E> spliterator()
.источник