简体   繁体   中英

Should I be exposing Stream<T> on my interface?

If I am writing .NET code I would often expose IEnumerable<T> where-ever it could possibly make sense. Maybe it was down to LINQ and the fact you could use foreach, but it felt "right" to do it.

private List<String> _myList;

public IEnumerable<String> MyList
{
    get { return _myList; }
}

Now I am writing Java 8 code and I am debating whether I should be exposing Stream<T> where possible in the same way? Maybe its because I have to call Collection.stream() and it feels like it is "doing work", but it doesn't feel right?

private Collection<String> myCollection;

public Stream<String> getStuff() {
    return myCollection.stream();
}

Is Stream<T> meant to be exposed on an interface in the same way that IEnumerable<T> might be?

You are asking the wrong question. After all, it isn't hard to support both, eg

Collection<Foo> getStuff();
default Stream<Foo> stuff() {
    return getStuff().stream();
}

so code using your interface doesn't need an explicit stream() call, while implementors of the interface don't need to bother with it as well.

As you are always exposing a Stream support whether via Collection.stream() or explicitly, the question is whether you want to expose the Collection . While it is cheap to provide a Stream for a Collection back-end it might turn out to be expensive to collect a Collection from a Stream .

So an interface exposing both ways suggests that they are equally usable while for an implementation not using a Collection back-end one of these methods might be way more expensive than the other.

So if you are sure that all implementations, including future ones, will always use (or have to support) a Collection it might be useful to expose it though the API as Collection s support certain operations which Stream doesn't. That's especially true if you support modification of the underlying data via the exposed Collection .

Otherwise, supporting Stream access only might be the better choice. This gives implementations the freedom to have other back-ends than a Collection . However, that also implies that this API does not support Java versions prior to Java 8.

Whether or not you want to be a Stream yourself, primarily depends on whether you're truly a Stream with the corresponding powers, ie support parallelization (not all Stream s do, but it's one of the many benefits of Stream s, and it's an important one). Normally I'd rather be a Collection and let myself be Stream ed by the corresponding API calls.

The getStuff() method, returning Stream<String> from myCollection.stream() looks right to me.

Avoid Stream where possible in interfaces.

Streams may * be finite or infinite * be sequential or parallel * be ordered or non-ordered * need closing or not

Neither the implementors of an interface nor the clients of the interface can know which of these characteristics should (not) apply or which they need to guard against.

Choosing the most flexible return type in an interface just means that clients have the full burden of guarding against all possibilities. It is generally much more useful in an interface to restrict the returned datatype so that implementors know what assumptions they can rely one (for the same reason returning Collection itself is not very useful in most cases, it is more useful to return List, Set, Iterable, InputStream to indicate rights and duties of clients when consuming the data).

And when you need to change the characteristics of the returned data, change the interface,b break your clients intentionally, so that they can update their algorithms to the changed situation.

That's much more useful than to say: "My method returns a Stream, so now I can return an infinite stream instead of a finite one, and the client code still compiles, how wonderful!". It is not wonderful, it is a horrible source of bugs to do that. Client code should NOT continue to compile with such drastic changes, so using datatypes that are explicit about finity, parallelity, orderedness and duty to close() is a much better choice.

Think like this: If remaining flexible was so great, then all interfaces that in Java7 return List or Set or Queue would be returning Iterable instead, to remain flexible in what datatype to actually return. But this is not what most interfaces do returning a Collection instead tells clients they can safely rely on a size() method, and returning a Set means they can safely rely on non-duplication, as an example. Being specific and restrictive in interfaces is not a sin, it is a virtue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM