How can I create a stream of <Interface> objects?

Viewed 444

Let's say I have:

interface SomeInterface {       
   Foo getFoo();
}

and

class SomeClass implements SomeInterface {
    Foo getFoo() {
       //returns a Foo object
    }
}

Then in a service, I have:

List<SomeClass> getItems() {
   //returns a list of SomeClass objects
}

It is not allowed to do the following:

Stream<SomeInterface> items = service.getItems().stream();

But ultimately, I have other classes that would share this interface and would want to do:

someMethod(Stream<SomeInterface> items) {
   //some operation
}

Is there a way around this? Like using flatMap? (I noticed that if I have a wrapper class on a List of SomeClass objects, I can flatMap the wrapper to return a stream of SomeInterface objects.)

I didn't find similar questions and don't readily see the solution. Could be something easy I'm missing. Java 14.

5 Answers

If your goal is to let someMethod accept Streams of SomeInterface interface along with its subtypes then you can use

/*someReturnTypeHere*/ someMethod(Stream<? extends SomeInterface> items){
   //some operation
}

One option is to explicitly map the stream with a cast:

Stream<SomeInterface> items = service.getItems().stream().map(SomeInterface.class::cast);

Without changing anything else, you can just use java wildcards and generics.

Stream<? extends SomeInterface> items = service.getItems().stream();

The ? means "anything, no matter what, that extends the interface SomeInterface" and such will work with your SomeClass ( and any other class that extends that interface)

More info: https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

Example code:

    public static void main(String args[]) {
    
            SomeService service = new SomeService();
            Stream<? extends SomeInterface> stream = service.getItems().stream();
        }
    
        public static class Foo {
    
        }
    
        public static interface SomeInterface {
            Foo getFoo();
        }
    
        public static class SomeClass implements SomeInterface {
            @Override
            public Foo getFoo() {
                return null;
            }
        }
    
        public static class SomeService {
            public List<SomeClass> getItems() {
                return new ArrayList<>();
            }
        }
    }

Why not just make the getItems() return a list of List<SomeInterface>

public List<SomeInterface> getItems()

and then just call:

Stream<SomeInterface> items = service.getItems().stream();

Another option similar to what was pointed out in the comments would be to do:

Stream<? extends SomeInterface> stream = service.getItems().stream();

If you cant change method signature of getItems() you can map the stream:

import java.util.List;
import java.util.ArrayList;
import java.util.stream.Stream;

public class StreamsDemo {
    
    static interface SomeInterface {
        String getFoo();
    }

    static class SomeClass implements SomeInterface {
        @Override
        public String getFoo() {
            return "hello";
        }
    }

    static class SomeService {

        List<SomeClass> getFoos() {
            List<SomeClass> list = new ArrayList<>();
            list.add(new SomeClass());
            list.add(new SomeClass());
            return list;
        }
    }

    public static void main(String... args) {
        Stream<SomeInterface> stream = new SomeService().getFoos()
                                                        .stream()
                                                        .map(SomeInterface.class::cast);
        stream.forEach(some -> System.out.println(some.getFoo()));
    }
}
Related