Can streams create new objects?
I
will try to simplify the situation I am facing. There are 2 entities:
class Foo {
String fooProperty;
@OneToOne
Bar bar;
}
class Bar {
String barProperty;
}
There is also a DTO class with attributes for Foo and Bar:
class FooDto {
String fooProperty;
String barProperty;
public static FooDto from(Foo foo) {
return new FooDto(foo.fooProperty, foo.bar.barProperty);
}
}
FooDto is used to transfer large amounts of data and can be easily transformed using streams:
fooList.stream().map(FooDto::from).( ...)
Now, the requirements have changed and a Foo can have multiple Bars:
@OneToMany
List<Bar> bar;
It is also required to generate a FooDto for each included Bar, like this:
Foo(fooProperty="foo1", bar=[Bar(barProperty="bar1"), Bar(barProperty="bar2")])
will be converted to:
[FooDto(fooProperty="foo1", barProperty="bar1"), FooDto(fooProperty="foo1", barProperty="bar2")]
I
managed to solve it with the middle list, but I’m still not sure if it’s the best solution.
I was wondering if it was possible to do something similar using pure streaming. I can use map and filter and generate size equal to/less than
Original input, but I don’t know how to generate a result with more elements.
Solution
The action you’re looking for is called flatMap
.
It operates on the stream of Foo
objects, taking as a parameter a function that converts the Foo
object to a FooDto object stream and returns the stream composition stream
of the FooDto
object:
class FooDto {
String fooProperty;
String barProperty;
public FooDto(String fooProperty, String barProperty) {
this.fooProperty = fooProperty;
this.barProperty = barProperty;
}
public static Stream<FooDto> from(Foo foo) {
return foo.bars.stream().map(bar -> new FooDto(foo.fooProperty, bar.barProperty));
}
}
And then:
List<FooDto> result = fooList.stream().flatMap(FooDto::from).( Collectors.toList());