Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is possible to know the size of a stream without using a terminal operation

I have 3 interfaces

public interface IGhOrg {
    int getId();

    String getLogin();

    String getName();

    String getLocation();

    Stream<IGhRepo> getRepos();
}

public interface IGhRepo {
    int getId();

    int getSize();

    int getWatchersCount();

    String getLanguage();

    Stream<IGhUser> getContributors();
}

public interface IGhUser {
    int getId();

    String getLogin();

    String getName();

    String getCompany();

    Stream<IGhOrg> getOrgs();
}

and I need to implement Optional<IGhRepo> highestContributors(Stream<IGhOrg> organizations)

this method returns a IGhRepo with most Contributors(getContributors())

I tried this

Optional<IGhRepo> highestContributors(Stream<IGhOrg> organizations){
    return organizations
            .flatMap(IGhOrg::getRepos)
            .max((repo1,repo2)-> (int)repo1.getContributors().count() - (int)repo2.getContributors().count() );
}

but it gives me the

java.lang.IllegalStateException: stream has already been operated upon or closed

I understand that count() is a terminal operation in Stream but I can't solve this problem, please help!

thanks

like image 313
MauroAlmeida Avatar asked Dec 15 '22 05:12

MauroAlmeida


2 Answers

Is possible to know the size of a stream without using a terminal operation

No it's not, because streams can be infinite or generate output on demand. It's not necessary that they are backed by collections.

but it gives me the

java.lang.IllegalStateException: stream has already been operated upon or closed

That's becase you are returning the same stream instance on each method invocation. You should return a new Stream instead.

I understand that count() is a terminal operation in Stream but I can't solve this problem, please help!

IMHO you are misusing the streams here. Performance and simplicity wise it's much better that you return some Collection<XXX> instead of Stream<XXX>

like image 175
Svetlin Zarev Avatar answered May 27 '23 18:05

Svetlin Zarev


You don't specify this, but it looks like some or possibly all of the interface methods that return Stream<...> values don't return a fresh stream each time they are called.

This seems problematic to me from an API point of view, as it means each of these streams, and a fair chunk of the object's functionality can be used at most once.

You may be able to solve the particular problem you are having by ensuring that the stream from each object is used only once in the method, something like this:

Optional<IGhRepo> highestContributors(Stream<IGhOrg> organizations) {
  return organizations
      .flatMap(IGhOrg::getRepos)
      .distinct()
      .map(repo -> new AbstractMap.SimpleEntry<>(repo, repo.getContributors().count()))
      .max(Map.Entry.comparingByValue())
      .map(Map.Entry::getKey);
}

Unfortunately it looks like you will now be stuck if you want to (for example) print a list of the contributors, as the stream returned from getContributors() for the returned IGhRepo has already been consumed.

You might want to consider having your implementation objects return a fresh stream each time a stream returning method is called.

like image 20
clstrfsck Avatar answered May 27 '23 18:05

clstrfsck