Reputation: 460
I am trying to iterate over nested java object and from nested object I'm trying to populate a map using Java 8.
Here is the list and structure of objects
IssueTypeDto.java
public class IssueTypeDto {
private String id;
private String name;
private List<CustomFieldDto> customFields;
}
CustomFieldDto.java
private String id;
private TypeDto type;
I am getting List
of IssueTypeDto
as response. Each IssueTypeDto
object can have a list of CustomFieldDto
objects. My requirement is I need to iterate over a list of IssueTypeDto
objects and for each CustomFieldDto
object I need to get id
and the corresponding TypeDto
object and insert it into a map as key and value. Here is what I am trying to do currently
Map<String, TypeDto> map = issueTypes.stream()
.flatMap(issueType->issueType.getCustomFields().stream()
.collect(Collectors.toMap(
CustomFieldDto::getId,
CustomFieldDto::getType)));
But i am getting compile time error as Type mismatch:
cannot convert from Stream<Object> to Map<String,TypeDto>"
I am new to Java 8 streams. So I am not able to figure out the issue. Any help would be appreciated.
Upvotes: 1
Views: 1235
Reputation: 166
Let's know the general concepts. You want to transform one object to another one. It can be 1 to 1 relationship or 1 to many. In case of 1 to 1 you need to use .map. 1 to many - .flatMap. So in other words map convert Object A to Object B. flatMap convert Object A to Stream of Object B. You was near you missed ')'.
Your case should be like this:
issueTypes.stream()
.flatMap(issueType -> issueType.getCustomFields().stream())
.collect(Collectors.toMap(CustomFieldDto::getId CustomFieldDto::getType));
Also please be sure that there are no duplicates on keys of different objects, otherwise Collectors.toMap() will throw exception due to key duplication.
Upvotes: 2
Reputation: 28968
The code you've provided does not compile for two reasons:
flatMap()
is an intermediate operation which expects a function that returns a stream as an argument. Instead, you've created a nested stream that generates a map. Therefore, your function doesn't match what flatMap()
expects.
Your stream pipeline lacks the terminal operation, therefore this assignment is incorrect
Map<String, TypeDto> map = issueTypes.stream().flatMap();
There's a map on the left side and a stream on the right side (because flatMap()
is an intermediate operation, returns you stream).
To fix it, you need to make the function passed into the flatMap()
return a stream, and add a terminal operation to the pipeline, i.e. produce the result from the main stream by moving collect()
out from the flatMap()
.
That's how it can be done by using Collectors.toMap()
(in the comments you've mentioned that there could be duplicated id
s ):
Map<String, TypeDto> map = issueTypes.stream()
.flatMap(issueType -> issueType.getCustomFields().stream())
.collect(Collectors.toMap(
CustomFieldDto::getId, // mapping a key
CustomFieldDto::getType, // mapping a value
(left, right) -> left // resolving duplicates - preserve the first encountered value
));
Another way of handling duplicates is preserve all of them by storing values mapped to the same key into a list, which can be done with Collectors.groupingBy()
:
Map<String, List<TypeDto>> map = issueTypes.stream()
.flatMap(issueType -> issueType.getCustomFields().stream())
.collect(Collectors.groupingBy(CustomFieldDto::getId));
Upvotes: 2