6
@FunctionalInterface
public interface Streamable<T> extends Iterable<T>, Supplier<Stream<T>>

I was exploring the Streamable Interface and the first method that I came across was the empty() method that has the following definition.

static <T> Streamable<T> empty() {
        return Collections::emptyIterator;
    }

Collections::emptyIterator returns the Iterator<T> but the return type of this method is Streamable<T>. Streamble extends Iterable and Supplier and not Iterator interface.

I didn't understand how is that working fine. Can someone please help me in understanding this?

I'm just failing in understanding the concept here. I wanted to know how is this working as I'm aware of how Inheritance works, but I'm unable to figure it out. I think I'm missing something here.

Michał Krzywański
  • 15,659
  • 4
  • 36
  • 63
Raj Wadhwa
  • 335
  • 2
  • 13
  • 4
    Wasn't this interface removed from jdk? Check [this](https://stackoverflow.com/questions/21985854/what-happened-to-java-util-stream-streamable) – Michał Krzywański Jul 31 '19 at 07:56
  • 2
    Which `Streamable` interface are you referring to? Can you post the full interface (or a reference to its javadoc)? – Eran Jul 31 '19 at 08:05
  • @Eran I'm talking about this: org.springframework.data.util.Streamable. – Raj Wadhwa Jul 31 '19 at 10:06
  • @RajWadhwa great, my answer applies to that interface. You should mention that in the body of the question. – Eran Jul 31 '19 at 10:08

2 Answers2

5

empty() returns a method reference Collections::emptyIterator.

In order for this code to pass compilation, that method reference must conform with the single abstract method of the Streamable<> interface.

Collections's emptyIterator() takes no arguments and returns an Iterator<T>.

Streamable<> extends both Iterable<T> and Supplier<Stream<T>>, which means it has to implement two methods (iterator() and get()), but one of them cannot be abstract (otherwise it wouldn't be a functional interface).

Collections's emptyIterator() can conform with Iterable<T>'s Iterator<T> iterator() signature.

So if Streamable<T> has a default implementation of Supplier<Stream<T>>'s get() method (if it doesn't, Streamable<T> cannot be a functional interface), Collections::emptyIterator can implement the Streamable<T> interface.

EDIT: If you were referring to org.springframework.data.util.Streamable, you can see that it does have a default implementation of get():

/*
 * (non-Javadoc)
 * @see java.util.function.Supplier#get()
 */
default Stream<T> get() {
    return stream();
}

Hence, any method reference that conforms with the single abstract method Iterator<T> iterator(), can implement that interface. Therefore Collections::emptyIterator can implement Streamable<T>.

Eran
  • 387,369
  • 54
  • 702
  • 768
3

For the record, this is the fully qualified name : org.springframework.data.util.Streamable.

The thing is that in the current context :

static <T> Streamable<T> empty() {    
    return Collections.emptyIterator();
}

is not the same thing than :

static <T> Streamable<T> empty() {    
    return Collections::emptyIterator;
}

return Collections.emptyIterator() returns an Iterator object while the method expects a Streamable. That indeed cannot compile as you supposed.

But return Collections::emptyIterator doesn't return an Iterator object. Instead, it defines the lambda body associated to the Streamable functional interface object returned by empty().

In fact this method reference :

return Collections::emptyIterator;

is equivalent to :

return () -> Collections.emptyIterator();

Why is it valid ?
Because Streamable is a functional interface defined as a function : ()-> Iterator<T> and emptyIterator() returns Iterator<T>.

davidxxx
  • 125,838
  • 23
  • 214
  • 215