DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. Java
  4. JVM Calendar: 19 Lessons in a Kata

JVM Calendar: 19 Lessons in a Kata

Here's how you can truly master Kata.

Donald Raab user avatar by
Donald Raab
·
Jan. 22, 19 · Presentation
Like (14)
Save
Tweet
Share
12.38K Views

Join the DZone community and get the full member experience.

Join For Free

We Learn Best by Doing

In this blog, I will show you how to get started coding the Eclipse Collections Pet Kata. If you want to become proficient in Eclipse Collections, you should practice the Kata on your own. In order to truly master the Kata, try teaching the Kata to others, teaching results in deeper learning.

Follow the Leader

There are slides online that I will walk through, as well as links to the code in GitHub. I will complete the first exercise of the Pet Kata. There are four failing tests in which I will demonstrate 19 different solutions. Follow along in your Java IDE, try the different solutions that I share below.

Step 1: Download Eclipse Collections Kata

  • Clone the repo here— https://github.com/eclipse/eclipse-collections-kata
  • Import the pom.xml file located in the root as a Maven Project in your Java IDE
  • Select the Pet Kata folder and go to the tests directory
  • Start with Exercise 1
  • Run the unit tests — they should fail!
  • Get the tests to pass one by one
  • When you complete the last exercise — Congratulations!
  • Star our repo if you enjoy the kata

The Slides

The online slides for the tutorial portion of the Pet Kata can be found here.

Understanding the Pet Kata Domain

Person, Pet, and PetType are the domain classes in the Kata. A Person can have zero or more pets. Each Pet has exactly one PetType. PetType is an enum. See the domain model for more details.

Exercise 1 — Lessons

Collect Pattern

The collect pattern is used to transform one collection type to another. This pattern is also known as map or transform.

Select Pattern

The select pattern is used to filter a collection on a positive condition. This pattern is also known as filter.

Exercise 1 — Fix the Failing Tests

Test # 1 — Get First Names of People

@Test
public void getFirstNamesOfAllPeople()
{
    // Replace null, with a transformation method on MutableList.
    MutableList<String> firstNames = null; // this.people...

    MutableList<String> expectedFirstNames = 
            Lists.mutable.with("Mary", "Bob", "Ted", "Jake", "Barry", "Terry", "Harry", "John");
    Assert.assertEquals(expectedFirstNames, firstNames);
}


In the first test, we need to write the code to collect the names of the people contained in “this.people." The names returned should match the value of  expectedFirstNames. The collect method takes a Function as a parameter. I will replace the null value for the firstNames variable with different solutions.

Solution (1) – Use a Lambda with collect

MutableList<String> firstNames = 
    this.people.collect(person -> person.getFirstName());


Solution (2) – Use a Method Reference with collect

MutableList<String> firstNames = 
    this.people.collect(Person::getFirstName);


I prefer using method references whenever possible. Method references are more succinct and are often self-documenting.

Solution (3) – Use a Java Stream with Collectors2

MutableList<String> firstNames =
    this.people.stream()
        .map(Person::getFirstName)
        .collect(Collectors2.toList());


Eclipse Collections has a static utility class named Collectors2. There are Collector implementations on this class that return Eclipse Collections types.

Solution (4) – Use an Anonymous Inner Class with collect

MutableList<String> firstNames =
    this.people.collect(new Function<Person, String>()
    {
        @Override
        public String valueOf(Person person)
        {
            return person.getFirstName();
        }
    });


I would not usually write code like this in Java 8 or above. However, it is useful sometimes if you want to see all of the types that are involved. Most noteworthy, this code will still work in any version of Java after Java 5.

Test #2 —Get Names of Mary Smith's Pets

@Test
public void getNamesOfMarySmithsPets()
{
    Person person = this.getPersonNamed("Mary Smith");
    MutableList<Pet> pets = person.getPets();

    // Replace null, with a transformation method on MutableList.
    MutableList<String> names = null; // pets...

    Assert.assertEquals("Tabby", names.makeString());
}


In the second test, we want to collect the names of “Mary Smith’s” pets. Mary Smith has one pet named “Tabby." Repetition is good for learning. We will use the collect method again to obtain the names of “Mary Smith’s” pets.

Solution (5) – Use a Lambda with collect

MutableList<String> names = pets.collect(pet -> pet.getName());


Solution (6) – Use a Method Reference with collect

MutableList<String> names = pets.collect(Pet::getName);


Solution (7) – Use a Java Stream with Collectors2

MutableList<String> names = pets.stream()
    .map(Pet::getName)
    .collect(Collectors2.toList());


Solution (8) – Use an Anonymous Inner Class with collect

MutableList<String> names = 
    pets.collect(new Function<Pet, String>()
        {
            @Override
            public String valueOf(Pet pet)
            {
                return pet.getName();
            }
        });


Test #3 — Get People With Cats

@Test
public void getPeopleWithCats()
{
    // Replace null, with a positive filtering method on MutableList.
    MutableList<Person> peopleWithCats = null;  // this.people...

    Verify.assertSize(2, peopleWithCats);
}


In the third test, we want to find all of the people who have cats. As a result, we will use the select method. The select method takes a Predicate as a parameter.

Solution (9) – Use a Lambda with select

MutableList<Person> peopleWithCats =
    this.people.select(person -> person.hasPet(PetType.CAT));


Solution (10) – Use a Method Reference with selectWith

MutableList<Person> peopleWithCats =
    this.people.selectWith(Person::hasPet, PetType.CAT);


We cannot use a method reference with the select method in this example. We can use the method selectWith, which takes a Predicate2 and a parameter.

Solution (11) – Use a Java Stream with Collectors2

MutableList<Person> peopleWithCats =
    this.people.stream()
        .filter(person -> person.hasPet(PetType.CAT))
        .collect(Collectors2.toList());


We cannot use a method reference with the filter method in this case.

Solution (12) – Use a Java Stream with Collectors2.selectWith()

MutableList<Person> peopleWithCats =
    this.people.stream()
        .collect(Collectors2.selectWith(
            Person::hasPet,
            PetType.CAT,
            Lists.mutable::empty));


We can use a method reference with the selectWith method on Collectors2. The selectWith method takes three parameters — a Predicate2, a parameter to pass to the Predicate2 and finally, a Supplier.


Solution (13) – Use reduceInPlace with Collectors.selectWith()

MutableList<Person> peopleWithCats =
    this.people.reduceInPlace(Collectors2.selectWith(
                Person::hasPet,
                PetType.CAT,
                Lists.mutable::empty));


We can reduce the boilerplate of stream().collect() by just calling reduceInPlace().

Solution (14) – Use an Anonymous Inner Class with select

MutableList<Person> peopleWithCats =
    this.people.select(new Predicate<Person>() 
    {
        @Override
        public boolean accept(Person person)
        {
            return person.hasPet(PetType.CAT);
        }
    });


Solution (15) – Use an Anonymous Inner Class with selectWith

MutableList<Person> peopleWithCats =
    this.people.selectWith(new Predicate2<Person, PetType>() 
    {
        @Override
        public boolean accept(Person person, PetType petType)
        {
            return person.hasPet(petType);
        }
    }, PetType.CAT);


Test #4 — Get People Without Cats 

@Test
public void getPeopleWithoutCats()
{
    // Replace null, with a negative filtering method on MutableList.
    MutableList<Person> peopleWithoutCats = null;  // this.people...

    Verify.assertSize(6, peopleWithoutCats);
}


In the final test, we want to find all of the people who do not have cats. There is a natural opposite to select available in Eclipse Collections. The method named reject filters based on the negative result of applying a Predicate.

Solution (16) – Use a Lambda with reject

MutableList<Person> peopleWithoutCats =
    this.people.reject(person -> person.hasPet(PetType.CAT));


Solution (17) – Use a Method Reference with rejectWith

MutableList<Person> peopleWithoutCats =
    this.people.rejectWith(Person::hasPet, PetType.CAT);


Eclipse Collections has good symmetry in its API. As a result, since there is a selectWith method, there is a rejectWith counterpart.

Solution (18) – Use a Java Stream with Collectors2

MutableList<Person> peopleWithoutCats =
    this.people.stream()
        .collect(Collectors2.rejectWith(
            Person::hasPet,
            PetType.CAT,
            Lists.mutable::empty));


There is no natural opposite of filter in Java Streams (filter IN vs. filter OUT). However, we can use rejectWith method available on Collectors2 with a method reference.

Solution (19) – Use an Anonymous Inner Class with reject

MutableList<Person> peopleWithoutCats =
    this.people.reject(new Predicate<Person>() 
    {
        @Override
        public boolean accept(Person person)
        {
            return person.hasPet(PetType.CAT);
        }
    });


For Further Study

Try solving the Eclipse Collections Pet Kata on your own, you should use method references and lambdas. Use Java Streams with and without Collectors2. Experiment with primitive collections in the later exercises. See how different JVM language like Groovy, Kotlin, or Scala can solve the Kata. There is an amazing amount of potential for learning just on the first exercise alone.

Eclipse Collections is open for contributions. You can also contribute to the Kata. If you like the library, you can let us know by starring it on GitHub.

Java (programming language) Kata (programming) Java virtual machine unit test Calendar (Apple)

Published at DZone with permission of Donald Raab. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Apache Kafka vs. Memphis.dev
  • Memory Debugging: A Deep Level of Insight
  • When AI Strengthens Good Old Chatbots: A Brief History of Conversational AI
  • Handling Automatic ID Generation in PostgreSQL With Node.js and Sequelize

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: