Happy Holidays!
It’s time for some Java Reindeer games.
This blog is going to be mostly code. I am going to demonstrate some Eclipse Collections and Java Stream APIs, with a holiday twist. I’ll start by implementing a Reindeer Enum in Java with some help from .
public enum Reindeer
{
Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen,
Rudolph;
public static ImmutableList<Reindeer> all()
{
return theMostFamousReindeerOfAll()
.newWithAll(theOtherReindeer()
.flatCollect(Reindeer::toList));
}
private static ImmutableList<Twin<Reindeer>> theOtherReindeer()
{
return Lists.immutable.with(
Dasher.and(Dancer),
Prancer.and(Vixen),
Comet.and(Cupid),
Donner.and(Blitzen));
}
private static ImmutableList<Reindeer> theMostFamousReindeerOfAll()
{
return Lists.immutable.with(Reindeer.Rudolph);
}
private static ImmutableList<Reindeer> toList(Twin<Reindeer> twin)
{
return Lists.immutable.with(twin.getOne(), twin.getTwo());
}
public Twin<Reindeer> and(Reindeer other)
{
return Tuples.twin(this, other);
}
public int nameLength()
{
return this.name().length();
}
public Character firstLetterOfName()
{
return Character.valueOf(this.name().charAt(0));
}
}
First, I create an of Reindeer with Rudolph at the front in the method named
all
. I create an ImmutableList
of pairs of all of the other reindeer, based on their usual order in the popular song. I use the type , which is a
that has the same type for both items. Finally, I used the method
to flatten all of the pairs of Reindeer into a single list which is appended to the
ImmutableList
with Rudolph using the method.
Now I will implement some tests for the Reindeer name games.
/**
* Create a comma separated String of the Reindeer names.
*/
@Test
public void reindeerNameGame1()
{
String expectedNames = "Rudolph, " +
"Dasher, Dancer, " +
"Prancer, Vixen, " +
"Comet, Cupid, " +
"Donner, Blitzen";
Assert.assertEquals(
expectedNames,
Reindeer.all().makeString(", "));
Assert.assertEquals(
expectedNames,
String.join(", ",
Reindeer.all()
.asLazy()
.collect(Reindeer::name)));
Assert.assertEquals(
expectedNames,
Reindeer.all()
.stream()
.map(Reindeer::name)
.collect(Collectors.joining(", ")));
}
In this test, I show three different ways a comma separated String of the reindeer names can be created. First, I use from Eclipse Collections. The method
does not require the object to be a
CharSequence
. It uses the toString
implementation of the Object.
Next, I use which was added in Java 8. This method takes an
Iterable
of CharSequence
, which I create using a with
.
Finally, I use a with the
ImmutableList
returned from all
and then map
each Reindeer
to its name
, and collect
them all into a String
using Collectors.joining
. All three approaches have the exact same result.
/**
* Count the Reindeer names based on their size.
*/
@Test
public void reindeerNameGame2()
{
IntBag nameCounts =
Reindeer.all()
.asLazy()
.collectInt(Reindeer::nameLength).toBag();
IntBag nameCountsFromIntStream =
IntBags.mutable.withAll(
Reindeer.all()
.stream()
.mapToInt(Reindeer::nameLength));
Assert.assertEquals(nameCounts, nameCountsFromIntStream);
Assert.assertEquals(3, nameCounts.occurrencesOf(5));
Assert.assertEquals(3, nameCounts.occurrencesOf(6));
Assert.assertEquals(3, nameCounts.occurrencesOf(7));
Bag<Integer> nameCountsBy =
Reindeer.all().countBy(Reindeer::nameLength);
Assert.assertEquals(3, nameCountsBy.occurrencesOf(5));
Assert.assertEquals(3, nameCountsBy.occurrencesOf(6));
Assert.assertEquals(3, nameCountsBy.occurrencesOf(7));
Map<Integer, Long> streamNameCounts =
Reindeer.all()
.stream()
.collect(Collectors.groupingBy(
Reindeer::nameLength,
Collectors.counting()));
Assert.assertEquals(new Long(3), streamNameCounts.get(5));
Assert.assertEquals(new Long(3), streamNameCounts.get(6));
Assert.assertEquals(new Long(3), streamNameCounts.get(7));
}
In this test, I show four different ways to count the names of the Reindeer by their length. First, I create an , by collecting all of the name lengths for the Reindeer using
and then converting the result
.
In the second case, I create an IntStream
from the Reindeer by mapping their name lengths to an int using mapToInt
. I use the method to create an
IntBag
from an IntStream
.
This method became available in Eclipse Collections 9.0 (Look at Item #3 for a comparison to previous versions). The third solution is the simplest. I use the method which is available on types that extend
in Eclipse Collections.
Finally, I use Stream
with Collectors.groupingBy
and which results in a
Map
of Integer
to Long
.
/**
* Group Reindeer by the first letter of their names.
*/
@Test
public void reindeerNameGame3()
{
Multimap<Character, Reindeer> multimap =
Reindeer.all().groupBy(Reindeer::firstLetterOfName);
Map<Character, List<Reindeer>> mapOfLists =
Reindeer.all()
.stream()
.collect(Collectors.groupingBy(
Reindeer::firstLetterOfName));
Assert.assertEquals("Dasher, Dancer, Donner",
multimap.get('D').makeString(", "));
Assert.assertEquals("Comet, Cupid",
multimap.get('C').makeString(", "));
Assert.assertEquals(multimap.get('D'), mapOfLists.get('D'));
Assert.assertEquals(multimap.get('C'), mapOfLists.get('C'));
}
In this test, I illustrate two ways to group Reindeer by the first letter of their last name. First, I use the method available directly on
ImmutableList
, which returns a .
In the second example, I use the stream method on and collect method on Stream with the groupingBy Collector
on the utility class.
I hope you enjoyed joining in these reindeer games. I explored a bunch of and APIs in these three examples that may be useful in your own Java code.
Have a Happy Holiday and Happy New Year!
is open for . If you like the library, you can let us know by starring it on GitHub.