Using JDK 8 Streams to Convert Between Collections of Wrapped Objects and Collections of Wrapper Objects
Join the DZone community and get the full member experience.
Join For FreeI have found Decorators and Adapters to be useful from time to time as I have worked with Java-based applications. These "wrappers" work well in a variety of situations and are fairly easy to understand and implement, but things can become a bit more tricky when a hierarchy of objects rather than a single object needs to be wrapped. In this blog post, I look at how Java 8 streams make it easier to convert between collections of objects and collections of objects that wrap those objects.
For this discussion, I'll apply two simple Java classes representing a Movie
class and a class that "wraps" that class called MovieWrapper
. The Movie
class was used in my post on JDK 8 enhancements to Java collections. The Movie
class and the class that wraps it are shown next.
package dustin.examples.jdk8.streams; import java.util.Objects; /** * Basic characteristics of a motion picture. * * @author Dustin */ public class Movie { /** Title of movie. */ private final String title; /** Year of movie's release. */ private final int yearReleased; /** Movie genre. */ private final Genre genre; /** MPAA Rating. */ private final MpaaRating mpaaRating; /** imdb.com Rating. */ private final int imdbTopRating; public Movie(final String newTitle, final int newYearReleased, final Genre newGenre, final MpaaRating newMpaaRating, final int newImdbTopRating) { this.title = newTitle; this.yearReleased = newYearReleased; this.genre = newGenre; this.mpaaRating = newMpaaRating; this.imdbTopRating = newImdbTopRating; } public String getTitle() { return this.title; } public int getYearReleased() { return this.yearReleased; } public Genre getGenre() { return this.genre; } public MpaaRating getMpaaRating() { return this.mpaaRating; } public int getImdbTopRating() { return this.imdbTopRating; } @Override public boolean equals(Object other) { if (!(other instanceof Movie)) { return false; } final Movie otherMovie = (Movie) other; return Objects.equals(this.title, otherMovie.title) && Objects.equals(this.yearReleased, otherMovie.yearReleased) && Objects.equals(this.genre, otherMovie.genre) && Objects.equals(this.mpaaRating, otherMovie.mpaaRating) && Objects.equals(this.imdbTopRating, otherMovie.imdbTopRating); } @Override public int hashCode() { return Objects.hash(this.title, this.yearReleased, this.genre, this.mpaaRating, this.imdbTopRating); } @Override public String toString() { return "Movie: " + this.title + " (" + this.yearReleased + "), " + this.genre + ", " + this.mpaaRating + ", " + this.imdbTopRating; } }
package dustin.examples.jdk8.streams; /** * Wraps a movie like a Decorator or Adapter might. * * @author Dustin */ public class MovieWrapper { private Movie wrappedMovie; public MovieWrapper(final Movie newMovie) { this.wrappedMovie = newMovie; } public Movie getWrappedMovie() { return this.wrappedMovie; } public void setWrappedMovie(final Movie newMovie) { this.wrappedMovie = newMovie; } public String getTitle() { return this.wrappedMovie.getTitle(); } public int getYearReleased() { return this.wrappedMovie.getYearReleased(); } public Genre getGenre() { return this.wrappedMovie.getGenre(); } public MpaaRating getMpaaRating() { return this.wrappedMovie.getMpaaRating(); } public int getImdbTopRating() { return this.wrappedMovie.getImdbTopRating(); } @Override public String toString() { return this.wrappedMovie.toString(); } }
With the Movie
and MovieWrapper
classes defined above, I now look at converting a collection of one of these into a collection of the other. Before JDK 8, a typical approach to convert a collection of Movie
objects into a collection of MovieWrapper
objects would to iterate over the source collection of Movie
objects and add each one to a new collection of MovieWrapper
objects. This is demonstrated in the next code listing.
// movies previously defined as Set<Movie> final Set<MovieWrapper> wrappedMovies1 = new HashSet<>(); for (final Movie movie : movies) { wrappedMovies1.add(new MovieWrapper(movie)); }
With JDK 8 streams, the operation above can now be implemented as shown in the next code listing.
Converting Collection of Wrapped Objects Into Collection of Wrapper Objects - JDK 8// movies previously defined as Set<Movie> final Set<MovieWrapper> wrappedMovies2 = movies.stream().map(movie -> new MovieWrapper(movie)).collect(Collectors.toSet());
Converting the other direction (from collection of wrapper objects to collection of wrapped objects) can be similarly compared to demonstrate how JDK 8 changes this. The next two code listings show the old way and the JDK 8 way.
Converting Collection of Wrapper Objects Into Collection of Wrapped Objectsfinal Set<Movie> newMovies1 = new HashSet(); for (final MovieWrapper wrappedMovie : wrappedMovies1) { newMovies1.add(wrappedMovie.getWrappedMovie()); }
final Set<Movie> newMovies2 = wrappedMovies2.stream().map(MovieWrapper::getWrappedMovie).collect(Collectors.toSet());
Like some of the examples in my post Stream-Powered Collections Functionality in JDK 8, the examples in this post demonstrate the power of aggregate operations provided in JDK 8. The advantages of these aggregate operations over traditional iteration include greater conciseness in the code, arguably (perhaps eventually) greater readability, and the advantages of internal iteration (including easier potential streams-supported parallelization). A good example of using streams and more complex Functions to convert between collections of less cohesively related objects is shown in Transform object into another type with Java 8.
Published at DZone with permission of Dustin Marx, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
A Deep Dive Into the Differences Between Kafka and Pulsar
-
Five Java Books Beginners and Professionals Should Read
-
Hiding Data in Cassandra
-
Alpha Testing Tutorial: A Comprehensive Guide With Best Practices
Comments