With an anonymous class:
ArrayList<Movie> movies = new ArrayList<>(Movies.movies());
movies.removeIf( new Predicate<Movie>()
{
@Override
public boolean test(Movie pMovie)
{
return pMovie.year() < 1960;
}
});
As a lambda expression:
movies.removeIf( movie -> movie.year() < 1960 );
If we add method isOld
to class Movie
:
public boolean isOld()
{
return aYear < 1960;
}
then the expression can use a method reference:
movies.removeIf(Movie::isOld);
With an anonymous class:
Movies.movies().forEach(new Consumer<Movie>()
{
@Override
public void accept(Movie pMovie)
{
System.out.println(pMovie);
}
});
With a lambda expression:
Movies.movies().forEach(movie -> System.out.println(movie));
With a reference to a static method, assumed to be in class Exercise3
:
Movies.movies().forEach(Exercise3::print);
private static void print(Movie pMovie)
{
System.out.println(pMovie);
}
And with a reference to System.out.println(Object)
:
Movies.movies().forEach(System.out::println);
List<Movie> movies = Movies.movies();
movies.sort((movie1, movie2) -> movie1.time() - movie2.time());
If we move the lambda expression to a static factory:
private static Comparator<Show> createByTimeComparator()
{
return (show1, show2) -> show1.time() - show2.time();
}
the client code becomes:
movies.sort(createByTimeComparator());
We transform the factory into a simple comparison method:
private static int compareByTime(Show pShow1, Show pShow2)
{
return pShow1.time() - pShow2.time();
}
We can then refer to it wherever a function type (Show,Show)->int
is expected:
movies.sort(Exercise5::compareByTime);
Assuming we have the static import:
import static java.util.Comparator.comparing;
the solution is:
List<Movie> movies = Movies.movies();
movies.sort(comparing(Movie::time).thenComparing(Movie::title));
As usual with the Flyweight pattern the first step is to make the constructor(s) private. Then we need a static flyweight store:
private static final Map<String, Movie> aMovies = new HashMap<>();
and a static accessor method:
public static Movie get(String pTitle, int pYear, int pTime)
{
return aMovies.computeIfAbsent(pTitle, title -> new Movie(pTitle, pYear, pTime));
}
In this simple exercise there's no way to get the year and time for a movie, so we have to provide all the information required to create an object (title, year, time) to the accessor method.
I created a helper function to turn a number of minutes into the requires output:
private static String toHHMM(int pMinutes)
{
assert pMinutes >=0;
return String.format("%d:%02d", pMinutes/60, pMinutes%60);
}
The solution is then:
Movies.movies().stream()
.map(Movie::time)
.map(Exercise8::toHHMM)
.forEach(System.out::println);
To make the code more readable I import the following static members:
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
The solution:
List<Movie> mySelection = Movies.movies().stream()
.filter(movie -> movie.year() < 2000)
.sorted(comparing(Movie::time).reversed())
.limit(3)
.sorted(comparing(Movie::title).reversed())
.collect(toList());
With integers:
Random random = new Random();
System.out.println(
IntStream.generate(()->random.nextInt(101))
.limit(1000000)
.summaryStatistics());
With doubles it's only a matter of changing the stream class and working around the 0-1.0
bounds for the random number generation:
DoubleStream.generate(()-> 100 * random.nextDouble())
.limit(1000000)
.summaryStatistics()
The following code assumes Predicate.isEqual
and Arrays.stream
are statically imported:
long result = Movies.movies().stream()
.map(Movie::title)
.map(String::toLowerCase)
.flatMap(string -> stream(string.split("[\\s,]+")))
.filter(isEqual("the"))
.count();
Movie result = Movies.movies().stream()
.reduce((movie1, movie2) ->
movie1.time() > movie2.time() ? movie1 : movie2).get();
This code assumes Collectors.toMap
has been statically imported.
Map<String, Integer> result =
Movies.movies().stream()
.collect(toMap(Movie::title, Movie::time));
This exercise is easier to organize with a helper function that returns the decade a Movie
was produced in, for example:
private static String decade(Movie pMovie)
{
return String.format("%02ds", ((pMovie.year()-1900)%100)/10*10);
}
Assuming Collectors.groupingBy
is statically imported, we have:
Map<String, List<Movie>> result =
Movies.movies().stream()
.collect(groupingBy(Exercise14::decade));
This solution relies on the fact that we can get a stream of all the entries in a Map
:
Movies.movies().stream()
.collect(groupingBy(Exercise15::decade))
.entrySet().stream()
.filter( entry -> entry.getKey().equals("50s") || entry.getKey().equals("60s"))
.flatMap( entry -> entry.getValue().stream() );
Unless otherwise noted, the content of this repository is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Copyright Martin P. Robillard 2019-2021