5 Ways to boost your code up using functional programming Style in Java

jmorla

Jorge L, Morla

Posted on April 24, 2020

5 Ways to boost your code up using functional programming Style in Java

Alt Text

The release of Java 8 on March, 2014 brought up a bunch of significant changes to the java world and and among the most important are Streams and Functional Programming.

The newer versions of java reinforced its use by adding quite useful new functionalities.

So today we'll turn java 7 and earlier code into Java 8+ Using Functional Style Programming.

1- Sort a Pets list using a non natural Order.

Prior java 8

        List<Pet> pets = new ArrayList<>();
        pets.add(new Pet("Scoby", 10));
        pets.add(new Pet("Jahnna", 12));
        pets.add(new Pet("Kira", 15));
        pets.add(new Pet("Snoopy", 2));
        pets.add(new Pet("Jeck" ,7));

        Collections.sort(pets, new Comparator<>() {
            @Override
            public int compare(Pet pet1, Pet pet2) {
                return (int) (pet1.getWeight() - pet2.getWeight());
            }
        });

       for(Pet pet : pets) {
            System.out.println(pet.getName());
       }
Enter fullscreen mode Exit fullscreen mode

Using Lambda and Streams Approach.

        List<Pet> pets = new ArrayList<>();
        pets.add(new Pet("Scoby", 10));
        pets.add(new Pet("Jahnna", 12));
        pets.add(new Pet("Kira", 15));
        pets.add(new Pet("Snoopy", 2));
        pets.add(new Pet("Jeck" ,7));

        pets.stream()
                .sorted((p1, p2) -> (int) (p1.getWeight() - p2.getWeight()))
                .forEach(Pet::getName);
Enter fullscreen mode Exit fullscreen mode

In the first example we had to provide a anonymous class that extends from Comparator and override the abstract behavior. Then pass it as a parameter to the Collections.sort method, because Pet class does not implement Comparable interface.

Using Java 8+, let's create a more descriptive code that expresses a what regardless of how.

2- Turn our pretty pets into wilds.

Java 7 or earlier.

        // pets List       

        List<WildAnimal> wild = new ArrayList<>();
        for(Pet p : pets) {
            WildAnimal animal = new WildAnimal(p.getName(), p.getWeight() * 2);
            wild.add(animal);

            animal.hunt();
        }
Enter fullscreen mode Exit fullscreen mode

Using Java 8 Features.

      // pets List
        pets.stream()
                .map(e -> new WildAnimal(e.getName(), e.getWeight() * 2))
                .forEach(WildAnimal::hunt);
Enter fullscreen mode Exit fullscreen mode

Now we are using the map() method to convert one type into another, in this case our tiny pets are now ruthless wild animals, and at the end for each of them we call hunt().

So far our 2 first examples were too Simple, let's fire some more interesting ones.

3- Calculate statistics from Jobs Applicants

Maybe you are working at home because of quarantine (or you've been working remote along before) and were asked for calculate some statistics given and countless list of job applicants. only taking who match the qualification criteria and theirs ages are between 20 and 35 years (just an example we don't want to be that exclusives). to make some business logic.

Let's see how can we do that using the old way.

        // applicants list ...
        int count = 0;
        int totalQualification = 0;
        double avgQualification;

        for (Applicant applicant : applicants) {
            if ((applicant.getAge() > 19 && applicant.getAge() < 36)
                    && applicant.getInterviewQualification() > 69) {
                count++;
                totalQualification += applicant.getInterviewQualification();
            }
        }

        avgQualification = count != 0 ? totalQualification / count : 0;
        System.out.format("Qualification stats {count=%d, total=%d, avg=%f}",
                count, totalQualification, avgQualification);
Enter fullscreen mode Exit fullscreen mode

Well not bad, but we can do better using java 9+

        // applicants list ...
        var stats = applicants.stream()
                .filter(a -> a.getAge() > 19 && a.getAge() < 36)
                .filter(a -> a.getInterviewQualification() > 6)
                .mapToInt(Applicant::getInterviewQualification)
                .summaryStatistics();

        System.out.format("Qualification stats {count=%d, total=%d, avg=%f}",
                stats.getCount(), stats.getSum(), stats.getAverage());
Enter fullscreen mode Exit fullscreen mode

Note: How we chain operations as if it were a pipeline, because in fact this is a pipeline.

4 - Group applicants by the position they applied.

Before

        Map<Position, List<Applicant>> group = new HashMap<>(); 
        for(Applicant ap: applicants) {
            List<Applicant> list = group.get(ap.getPosition());
            if(list == null){
                list = new ArrayList<>();
                group.put(ap.getPosition(), list);
            }
            list.add(ap);
        }
        System.out.println(group);  
Enter fullscreen mode Exit fullscreen mode

After

        Map<Position, List<Applicant>> group = applicants
                .stream()
                .collect(Collectors.groupingBy(Applicant::getPosition));

        System.out.println(group);
Enter fullscreen mode Exit fullscreen mode

The code looks much clearer in the second example, in this case we use the groupingBy collector which takes a Function as a parameter in this caseFunction <Applicant>. The method reference allows us to run the getPosition method from the current applicant being passed and use the return value as a group.

Our last example is going to use Dates.

5 - Grouping the last 7 days of statistical analysis about COVID-19

because you are bored and want to build another app to visualize Corona-virus statistics maybe this example could help.

Using the old way

        List<Summary> lastWeek = new ArrayList<>();

        Calendar calendar = GregorianCalendar.getInstance();
        calendar.setTime(new Date());

        for(int i = 0; i < 7; i++) {
            Date current = calendar.getTime();
            lastWeek.add(covid19DataSource.getSummaryByDate(current));
            calendar.add(Calendar.DAY_OF_MONTH, -1);
        }

        System.out.println(lastWeek);
Enter fullscreen mode Exit fullscreen mode

Using Java 9+

        LocalDate today = LocalDate.now().plusDays(1);

        List<Summary> lastWeek = today.minusDays(7).datesUntil(today, Period.ofDays(1))
                .map(covid19DataSource::getSummaryByDate)
                .collect(Collectors.toList());

                System.out.println(lastWeek);
Enter fullscreen mode Exit fullscreen mode

Here we are not only using lambda and Stream but also are using newer Java's time API. The datesUntil method was added in Java 9 allow us to get a Stream of LocalDate objects which we map to get the corresponding covid 19 summary and then just collect it into a list.

[Summary{confirmed=0, recovered=0, deaths=0, date=2020-04-17}, ...
Enter fullscreen mode Exit fullscreen mode

Both approaches return this same result, it'd be cool getting the same metrics in real life. :D

Thanks for reading, Keep safe :).

💖 💪 🙅 🚩
jmorla
Jorge L, Morla

Posted on April 24, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related