1

I want to generate a list of strings, comprising id and external ids, from a list of Bean.

public class User {
    private String id;
    private List<String> externalIds;
}

I got it using the below code, but here I need to do the stream twice.

List<User> references = new ArrayList();
Stream.concat(references.stream().map(User::getId),
references.stream().map(User::getExternalIds).flatMap(Collection::stream))
            .collect(Collectors.toList());

Is there any better way to rewrite this code?

3 Answers 3

8

Use Stream.concat inside the flatMap operation:

references.stream()
        .flatMap(user -> Stream.concat(
            Stream.of(user.getId()),
            user.getExternalIds().stream()
        ))
        .collect(Collectors.toList())
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the reply, this solution works, the only issue is if externalIds is null, then it will throw an error. I can initialize the list in bean to prevent this. Any other way do you think?
Allowing null collections, maps or arrays are usually bad to work with, because you need to add a lot of null checks. Using an empty collection/list/set, map or array is almost always better.
collect(Collectors.toList())can be replaced by toList()
@ciccioska indeed, if you're using Java 16 or later
1

Try this:

references.stream()
  .flatMap(u -> Stream.of(List.of(u.getId()), u.getExternalIds()))
  .flatMap(List::stream)
  .collect(Collectors.toList());

6 Comments

.flatMap(List::stream) is not working , its giving error ""Non-static method cannot be referenced from a static context""
I think that Bohemian tried to let the map step return a Stream<List<String>>, but it's a Stream<Stream<List<String>>>. You'd need to use flatMap(Function.identity()) to get a Stream<List<String>> back, then flatMap(List::stream) to get a Stream<String>.
@Rob I did get a little tangled there. Thanks for the hint, but you can avoid flatMap(Function.identity()) by flatMap instead of map first up. See latest edit.
@Bohemian you're right, the map returned a Stream, that can of course be done with flatMap immediately.
@Rob I'm going to go out on a limb and say this is more readable, because it first uplifts id to be the same type as externalIds, then takes care of business.
|
0

If you're using Java 16+ you can do it using mapMulti. This essentially intercepts each item in the stream and replaces it with other items. It avoids re-streaming and flatmapping. Since the nature of the stream(i.e. type) is being changed from User to String, the witness before mapMulti is required.

  • add the user id in the stream.
  • then add each external id in the stream for that user
List<String> results = references.stream()
        .<String>mapMulti((user, consumer) -> {
            consumer.accept(user.getId());
            for (String id : user.getExternalIds()) {
                consumer.accept(id);
            }
        }).toList();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.