Java 8 get all elements in list

A pattern I've found very useful is to let the parent class (in this case the Contact class) create and return the streams of children objects (in this case the share friends ids):

public class Contact {

    private List<String> sharedFriendsIds;

    public Stream<String> sharedFriendsIds() {
        return sharedFriendsIds == null ? Stream.empty() : sharedFriendsIds.stream();
    }

    public List<String> getSharedFriendsIds() {
        return sharedFriendsIds;
    }
}

The convention is to name the method that returns the stream as the attribute being streamed. This method already contains the null-check.

Then, getting the shared friends ids for all contacts is much easier:

List<String> sharedContacts = contactsList.stream()
        .flatMap(Contact::sharedFriendsIds)
        .collect(Collectors.toList());

You need to use flatMap() in order to flatten the elements of the child list into a single list, otherwise you'd get a list of streams.

Note 1: you don't need to use sequential(), since using stream() on the list of contacts already returns a sequential stream.

Note 2: if you want the final list to be sorted, then you should use sorted() on the stream:

List<String> sharedContacts = contactsList.stream()
        .flatMap(Contact::sharedFriendsIds)
        .sorted().collect(Collectors.toList());

You should use .flatMap() to create a single list from the sharedFriendsIds list that is contained in each Contact object from the main list contactsList. Please check;

List<String> sharedContacts = contactsList.stream()
        .map(Contact::getSharedFriendsIds)
        .filter(Objects::nonNull)
        .flatMap(Collection::stream)
        .sorted().collect(Collectors.toList());

The .filter() call is for the case when there is any Contact with sharedFriendsIds == null in the list, since that would cause NPE in the next line, we ought to filter those out. There are other ways to achieve that like;

- Optional

    List<String> sharedContacts = contactsList.stream()
            .flatMap(contacts -> Optional.ofNullable(contacts.getSharedFriendsIds())
                    .map(Collection::stream).orElseGet(Stream::empty))
            .sorted().collect(Collectors.toList());

  Where the filtering of null `sharedFriendsIds` are done in such a way that 
 they are absorbed into the `flatMap` logic as empty streams.

- emptyIfNull()

You can include collections dependency from apache.commons and use CollectionUtils.emptyIfNull method as follows;

    public static <T> Stream<T> collectionAsStream(Collection<T> collection) {
        return emptyIfNull(collection).stream();
    }

then call this from original stream like;

     List<String> sharedContacts = contactsList.stream()
             .map(Contact::getSharedFriendsIds)
             .flatMap(Foo::collectionAsStream)
             .sorted().collect(Collectors.toList());

Also you used .sequential for the sort logic, I guess, you should've used .sorted method, since sequential is for triggering non-parallel usage, which is already the default configuration of a Stream.


There is no reason to use .sequential() here, streams are sequential by default.

List<String> sharedContacts = contactsList.stream()
        .map(Contact::getSharedFriendsIds)
        .filter(Objects::nonNull)
        .flatMap(Collection::stream)
        .collect(Collectors.toList());

In natural order;

List<String> sharedContacts = contactsList.stream()
        .map(Contact::getSharedFriendsIds)
        .filter(Objects::nonNull)
        .flatMap(Collection::stream)
        .sorted().collect(Collectors.toList());