Archive for the ‘Java8’ Category

Lombok

Posted: June 9, 2018 in General, Java, Java8
Tags: , ,

Lets take a look at a following sample code.

import java.io.Serializable;
import java.util.Objects;

public class User implements Serializable {

    private long id;
    private String username;
    private String login;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id &&
                Objects.equals(username, user.username) &&
                Objects.equals(login, user.login);
    }

    @Override
    public int hashCode() {

        return Objects.hash(id, username, login);
    }
}

A class should have getter-setters for the instance variables, equals & hashCode method implementation, all field constructors and an implementation of toString method. This class so far has no business logic and even without it is 50+ lines of code. This is insane.

Lombok is used to reduce boilerplate code for model/data objects, e.g., it can generate getters and setters for those object automatically by using Lombok annotations. The easiest way is to use the @Data annotation.

import java.io.Serializable;
import lombok.data

@Data
public class User implements Serializable {

    private long id;
    private String username;
    private String login;
}

How to add Lombok to your java project ?

Using Gradle

dependencies {
    compileOnly('org.projectlombok:lombok:1.16.20')
}

Using Maven

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
</dependency>

Tips to remember while using Lombok

  1. Don’t mix logic with lombok
  2. Use @Data for your DAOs
  3. Use @Value for immutable value objects
  4. Use @Builder when you have an object with many fields with the same type
  5. Exclude generated classes from Sonar report. If you are using Maven and Sonar, you can do this using the sonar.exclusions property.
Advertisements

How can we process really large collections efficiently? Normally we used loops to iterate over a collection.

Lets say we need to iterate over a list of Person object

List<Person> personList = new ArrayList<>();
personList.add(new Person("Sam", 10));
personList.add(new Person("Smith", 9));
personList.add(new Person("Zayn", 2));
personList.add(new Person("Nathan", 1));

Using foreach loop

personList.forEach(person -> {
    System.out.println(" Person Name :: " + person.getName());
});

In Java 8, we have something new called “Stream”. A stream represents a sequence of elements and supports different kind of operations to perform computations upon those elements.

System.out.println("Traversing List using streams.");
personList.stream().forEach(person -> {
    System.out.println(person.getName());
});

It may seem Java 8’s stream api is a bit verbose than the for-each loop for collections. And we wonder what benefit can come from it.

The difference between for-each loop and using stream api (collection.stream()) in Java 8 is that, we can easily implement parallelism when using the stream api with collection.parallelStream(). Whereas, in for-each loop you will have to handle threads on your own.

/**One of the goals of the stream API in Java8 is to let you break up processing on a system that has multiple CPUs.
 * This multi CPU processing is handled automatically by the Java runtime.
 * All you need to do is turn your sequential stream into a parallel stream.
 */
System.out.println("Traversing List using Parellel streams");
personList.parallelStream().forEach(person -> {
    System.out.println(person.getName());
});

 

Stream operations are either intermediate or terminal. Intermediate operations return a stream so we can chain multiple intermediate operations without using semicolons. Terminal operations are either void or return a non-stream result. In the above example filter, map and sorted are intermediate operations whereas forEach is a terminal operation. For a full list of all available stream operations see the Stream Javadoc. Such a chain of stream operations as seen in the example below is also known as operation pipeline. 

Predicate<Person> agePredicate = person -> person.getAge() > 5;
System.out.println("Traversing List using Parellel streams and filters");
personList.parallelStream()
        .filter(nameAndAgePredicate)
        .sorted()
        .forEach(person -> {
    System.out.println(person.getName());
});

Lets see the different ways of creating stream

Arrays.asList("sam", "smith", "zayn")
        .stream()
        .findFirst()
        .ifPresent(System.out::println);

Stream.of("sam", "smith", "zayn")
        .findFirst()
        .ifPresent(s -> System.out.println(s));
Arrays.stream(new int[] {1, 2, 3})
        .average()
        .ifPresent(System.out::println);

In addition to the new lambda syntax, Java SE8 adds a number of new functional interfaces. One of the most useful is called the Predicate Interface which is an interface that has a single boolean method named Test, that you can use to wrap up your conditional processing, and make conditional code a lot cleaner.

Go through the following example and you will get an understanding of Predicate Interface

package com.suhas;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;


public class PredicateInterfaceTest {

    public static void main(String[] args) {

        List<Person> personList = new ArrayList<>();
        personList.add(new Person("Sam", 10));
        personList.add(new Person("Smith", 9));
        personList.add(new Person("Zayn", 6));
        personList.add(new Person("Nathan", 1));

        Predicate<Person> agePredicate = person -> person.getAge() > 5;

        Predicate<Person> namePredicate = person -> person.getName().equals("Zayn");

        Predicate<Person> nameAndAgePredicate = namePredicate.and(person -> person.getAge() < 5);

        personList.forEach(person -> {
            if (agePredicate.test(person))
                System.out.println("Matching Record Found for Age Predicate :: " + person.getName());
            if (namePredicate.test(person))
                System.out.println("Matching Record Found for Name Predicate :: " +  person.getName());
            if (nameAndAgePredicate.test(person))
                System.out.println("Matching Record Found for Name and Age Predicate :: " +  person.getName());

        });

    }
}

Java 8 introduced Optional<T> as a container object which may contain null values. It’s often used to indicate to a caller that a value might be null and that it need to be handled to avoid NullPointerExceptions.

With the release of Hibernate 5.2, we could use them in our persistence layer for optional entity attributes or when loading entities that may or may not exist.

Lets see how we can use Optional<T> to indicate optional attributes and query results which might not return a result.

Consider a sample Tour Booking app where i need to search a tour package by region. The database design has a 2 tables  ‘TourPackage’  and ‘CustomerReview’  The ‘TourPackage’ entity is the root in our entity aggregate. There can be a CustomerReview associated with every TourPackage but not mandatory.

So when we searched for a TourPackage by region, what if there was tour package for which the optional ‘customerReview’ attribute is null? With previous Java versions, the getCustomerReview() method would just return null. The caller would need to know about the possible null value and handle it. With Java 8, you can return an Optional to make the caller aware of possible null values and to avoid NullPointerExceptions.

But if you just change the type of the customerReview attribute from CustomerReview to Optional<CustomerReview>, Hibernate isn’t able to determine the type of the attribute and throws a MappingException.

javax.persistence.PersistenceException: [PersistenceUnit: my-persistence-unit] Unable to build Hibernate SessionFactory

Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Optional, at table: TourPackage, for columns: [org.hibernate.mapping.Column(customerReview)]

To avoid this Exception, you have to use field-type access and keep Attachment as the type of the attachment attribute. Hibernate is then able to determine the data type of the attribute but doesn’t return an Optional.

Lets see how we can see the comment given by the customer.

Optional<CustomerReview> customerReview = tourPackage.getCusomerReview();
if (customerReview.isPresent()) {
CustomerReview review = customerReview.get();
System.out.print(“Review Comment :: ” + review.getComment());
}

Lets also take a look at the various methods in the Optional class.

Optional.empty() – Return an empty Optional object.
Optional.of() – Return an Optional object with a non-null value. It will throw NullPointerException if value is null.
Optional.ofNullable() – Return an Optional object with a non-null value. It will return empty Optional object if value is null.
Optional#isPresent() – Return true if a value is present in the Optional object, otherwise false.
Optional#get() – Return a value from Optional object, if value is present, otherwise throws NoSuchElementException.
Optional#ifPresent() – This method invoke a Consumer if a value is present in Optional object, otherwise do nothing.
Optional#orElse() – Return a value if present, otherwise return other specified value.
Optional#orElseGet() – Return a value if present, otherwise invoke a Supplier that return other value.
Optional#orElseThrow() – Return a value if present, otherwise invoke a Supplier that create and throws an exception.
Optional#filter() – Return an Optional object if a value is present, and matches the given Predicate, otherwise return an empty Optional object.
Optional#map() – Return an Optional object if a value is present, and applies the given mapping Function to it, otherwise return an empty Optional object.
Optional#flatMap() – Return an Optional object if a value is present, and applies the provided Optional-bearing mapping Function to it, otherwise return an empty Optional object.