Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't there an Interface for something that provides a Stream<E>?

In order to keep implementation details from leaking, instead of returning, e.g., a Collection<MyCoolObject>, one might implement Iterable<MyCoolObject>, which would then require implementing Iterator<T> from the Iterable Interface. Thus however the internal data structure is managed, the access to the elements is via the Iterator.

With Java 8, one might wish to add Stream<MyCoolObject> stream() to MyCoolObject. (See also: recommendation to support stream in the book Java 8 Lambdas). While adding the method isn't difficult (and I did read the Question about Why Iterable Doesn't Provide Stream), it seems odd that Java did not add an Interface for Streamable<T> to mirror the Iterable<T> idea. (Well, a different name perhaps since Streamable exists for the ever use CORBA stuff).

I think I followed the Answer about why adding Stream to Iterable was potentially problematic, but I do not see why a Streaming<T> interface couldn't have been provided. For example, Collections could have implemented the Streaming<T> interface, and it would make it clearer for other objects that one could expect a stream() method.

Based upon an Answer to the above referenced Question, it is possible to get a Stream from the Iterable via

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

but that seems like a lot of work given that MyObject could would like to just implement stream() to allow a user of the object to do

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

without the intervening conversion from the iterator.

Is there a reason for the lack of an interface for streaming capable objects? Is there a better approach than just implementing stream() on MyCoolObject and letting someone look through the Javadoc so they know it has a stream() method?

Or, is quite likely, am I misunderstanding something about the approach for Stream?

(Also, I implement stream() in CoolObject, but then forget to implement parallelStream(), which is something that would be alleviated by having the interface).

like image 451
KevinO Avatar asked May 10 '17 20:05

KevinO


People also ask

What is a stream interface?

The stream head provides the interface between the stream and an application program. After a stream has been opened, STREAMS-related system calls enable a user process to insert and delete (push and pop) modules.

Which is the method to interact over a stream interface?

concat() Method of Stream Interface in Java API.

What fields are allowed in an interface?

All the members (methods and fields) of an interface are public. All the methods in an interface are public and abstract (except static and default). All the fields of an interface are public, static and, final by default.

What is a stream in Java?

A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. The features of Java stream are – A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.


2 Answers

This should probably augment any future answers.

I don't know why you think that returning an Iterable<MyCoolObject> rather than a Collection<MyCoolObject> is better. It might hide details indeed, and will create more problems as-well.

A Collection has a known size that plays a big role while splitting for parallel processing. This is reported as Spliterator.SIZED | Spliterator.SUBSIZED. So a Collection.stream will handle parallel streams much better then a Iterable, that will use:

public static <T> Spliterator<T> spliteratorUnknownSize 

that is documented as:

... and implements trySplit to permit limited parallelism.

Which is obvious, since you don't know the size at all. Under the current implementation the batch size is 1024. So, for example, for anything under 1024 elements you would not get any parallelisation at all.

Now as far as your question goes, there used to be such a thing in the early builds of jdk-8. It was called java.util.stream.Streamable. From what I know it was removed because there are methods that return a Stream, but not via the stream() method.

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

So the only place where this would be implemented would be the Collections. And that as far as I can tell this would be a really isolated place.

Aha moment

Here is the explanation from the people in charge of this.

As suggested here are the reasons for the removal:

I am considering dropping the Streamable interface. Currently the only implementor is Collection, and all of the other stream-bearing methods are serving up specialized streams (chars(), codePoints(), lines(), etc) with a method name that is more suitable than "stream". So I think we should drop Streamable and leave the stream() / parallel() methods on Collection (or possibly move them up Iterable).

like image 158
Eugene Avatar answered Oct 01 '22 01:10

Eugene


Because it was removed, but you can easily roll out your own Streamable implementation if you need it:

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

If we take the example of the strategy pattern, you would then define it like so:

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

Which can easily be implemented based on any backing object providing a method returning a Stream<T>, using a method reference. For example, if you have a collection:

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

If Collection was extending such a Streamable interface, you would indeed not need to use the method reference. But otherwise there didn't seem to be much added value to put that in the JDK – and it can still be added later if needed.

like image 37
Didier L Avatar answered Oct 01 '22 01:10

Didier L