Почему нет интерфейса для чего-то, что обеспечивает Stream <E>?

Чтобы не допустить, чтобы данные реализации не протекали, вместо того, чтобы возвращать, например, Collection<MyCoolObject>, можно было бы реализовать Iterable<MyCoolObject>, для чего потребовалось бы реализовать Iterator<T> из интерфейса Iterable. Таким образом, однако, структура внутренней структуры управляется, доступ к элементам осуществляется через Iterator.

С Java 8 можно добавить Stream<MyCoolObject> stream() в MyCoolObject. (См. Также: рекомендации по поддержке stream в книге Java 8 Lambdas). При добавлении метода это не сложно (и я прочитал Вопрос о Почему Iterable не предоставляет поток), кажется странным, что Java не добавила интерфейс для Streamable<T>, чтобы отразить идею Iterable<T>. (Ну, другое имя возможно, так как Streamable существует для когда-либо используемого материала CORBA).

Я думаю, что я последовал за ответом о том, почему добавление stream в Iterable было потенциально проблематичным, но я не понимаю, почему интерфейс Streaming<T> не мог быть предоставлен. Например, Collections мог бы реализовать интерфейс Streaming<T>, и он упростит для других объектов, что можно ожидать метод stream().

На основании ответа на упомянутый выше Вопрос, можно получить stream из Iterable через

Stream s = StreamSupport.stream(iter.spliterator(), false);

но это похоже на большую работу, учитывая, что MyObject мог бы просто реализовать stream(), чтобы позволить пользователю объекта

myObject.stream().filter(...).collect(...)

без промежуточного преобразования из итератора.

Есть ли причина отсутствия интерфейса для потоковой передачи объектов? Есть ли лучший подход, чем просто реализовать stream() в MyCoolObject и позволить кому-то просмотреть Javadoc, чтобы они знали, что у него есть метод stream()?

Или, вполне вероятно, я что-то не понимаю о подходе к Stream?

(Кроме того, я реализую stream() в CoolObject, но затем забудьте реализовать parallelStream(), что будет облегчено благодаря интерфейсу).

Ответы

Ответ 1

Это должно, вероятно, увеличить любые будущие ответы.

Я не знаю, почему вы думаете, что лучше вернуть Iterable<MyCoolObject>, а не Collection<MyCoolObject>. Это может скрыть подробности, и это создаст больше проблем.

В коллекции есть known size, которая играет большую роль при расщеплении для параллельной обработки. Об этом сообщается как Spliterator.SIZED | Spliterator.SUBSIZED. Таким образом, Collection.stream будет обрабатывать параллельные потоки намного лучше, чем Iterable, которые будут использовать:

public static <T> Spliterator<T> spliteratorUnknownSize 

который документируется как:

... и реализует trySplit для разрешения ограниченного parallelism.

Это очевидно, так как вы вообще не знаете размер. В текущей реализации размер партии 1024. Так, например, для чего-либо менее 1024 элементов вы не получите никакой параллелизации вообще.

Теперь, насколько ваш вопрос идет, в ранних сборках jdk-8 это было так. Он назывался java.util.stream.Streamable. Из того, что я знаю, оно было удалено, потому что есть методы, возвращающие Stream, но не через метод stream().

String::codePoints()
File::lines
Pattern::splitAsStream
... many others

Таким образом, единственным местом, где это будет реализовано, будет сбор. И это, насколько я могу судить, было бы действительно изолированным местом.

Аха момент

Ниже приведено объяснение от людей, ответственных за это.

Как показано здесь, причины устранения:

Я рассматриваю возможность отключения интерфейса Streamable. В настоящее время Реализация - это сборник, и все другие потоковые методы обслуживают специализированные потоки (chars(), codePoints(), lines() и т.д.), с именем метода, которое более подходит, чем "поток". Поэтому я думаю, что мы следует отключить Streamable и оставить методы stream()/parallel() на Коллекция (или, возможно, переместить их в Iterable).

Ответ 2

Поскольку он был удален, но вы можете легко реализовать свою собственную реализацию Streamable, если вам это нужно:

@FunctionalInterface
interface Streamable<T> {
    Stream<T> stream();
}

Если мы возьмем пример шаблона стратегии, вы тогда определите его так:

interface StreamStrategy<T> {
    Streamable<T> getStreamable();
}

который может быть легко реализован на основе любого объекта поддержки, предоставляющего метод, возвращающий Stream<T>, используя ссылку на метод. Например, если у вас есть коллекция:

class CollectionBasedStrategy<T> implements StreamStrategy<T> {
    @Override
    public Streamable<T> getStreamable() {
        return new ArrayList<T>()::stream;
    }
}

Если Collection расширяет такой интерфейс Streamable, вам действительно не нужно использовать ссылку на метод. Но в противном случае, похоже, не было много добавленной ценности, чтобы поместить это в JDK - и при необходимости он может быть добавлен позже.