JAVA 7 way v/s JAVA 8 way- Let’s get our hands dirty with Lambdas- Functional Programming in JAVA 8- Part 4

Java

Before reading this post kindly go from part 1 of this post to understand lambda expression.

http://jkoder.com/understanding-java-8-lambda-expression-functional-programming-in-java-8-part-1/

Here we will see practical difference between JAVA 7 and JAVA 8. We will create a list of Person objects and we will do below 3 things on it first by using JAVA 7 way then by JAVA 8 way.

  • Sort list by last name.
  • Create a method that prints all elements in the list./li>
  • Create a method that prints all people that have last name beginning with C.
public class ExerciseSolutionJava7 {

	public static void main(String[] args) {
		List<Person> people=Arrays.asList(
				new Person("Charles","Dickens",60),
				new Person("Lewis","Carroll",42),
				new Person("Thomas","Carlyle",51),
				new Person("Charlotte","Bronte",45),
				new Person("Matthew","Arnold",39));
		
		//Step 1: Sort list by last name
		Collections.sort(people, new Comparator<Person>() {
			@Override
			public int compare(Person p1, Person p2) {
				return p1.getLastName().compareTo(p2.getLastName());
			}
		});
		
		//Step 2: Create a method that prints all elements in the list
		printAll(people);
		
		//Step 3: Create a method that prints all people that have lastName beginning with C
		printLastNameBeginningWithC(people);
	}
	
	private static void printAll(List<Person> people) {
		for(Person p: people){
			System.out.println(p);
		}
	}

	private static void printLastNameBeginningWithC(List<Person> people) {
		for(Person p: people){
			if(p.getLastName().startsWith("C")){
				System.out.println(p);
			}
		}
	}
}

Pretty much straight forward. But, this is very very inflexible. What if requirement is to print persons with lastName beginning with “D”. So what you do? Write another method. Not ideal way.

Ideal way is to pass behaviour to printLastNameBeginningWithC function. Filtering should not be inside printLastNameBeginningWithC function, rather write an object that contains the filter and pass that object to the desired function. In JAVA 7 there is a way for it, passing in the behaviour by implementing the interface, here we will use anonymous inline implementation of interface. Instead of printLastNameBeginningWithC we will use printConditionally function name.

public class ExerciseSolutionJava7 {

	public static void main(String[] args) {
		List<Person> people=Arrays.asList(
				new Person("Charles","Dickens",60),
				new Person("Lewis","Carroll",42),
				new Person("Thomas","Carlyle",51),
				new Person("Charlotte","Bronte",45),
				new Person("Matthew","Arnold",39));
		
		//Step 1: Sort list by last name
		Collections.sort(people, new Comparator<Person>() {
			@Override
			public int compare(Person p1, Person p2) {
				return p1.getLastName().compareTo(p2.getLastName());
			}
		});
		
		//Step 2: Create a method that prints all elements in the list
		printAll(people);
		
		//Step 3: Create a method that prints all people that have lastName beginning with C
		printConditionally(people, new Condition() {	
			@Override
			public boolean test(Person p) {
				return p.getLastName().startsWith("C");
			}
		});
		
                //method that prints all people that have firstName beginning with C
		printConditionally(people, new Condition() {	
			@Override
			public boolean test(Person p) {
				return p.getFirstName().startsWith("C");
			}
		});
	}
	
	private static void printAll(List<Person> people) {
		for(Person p: people){
			System.out.println(p);
		}
	}
	
	private static void printConditionally(List<Person> people, Condition condition) {
		for(Person p: people){
			if(condition.test(p)){
				System.out.println(p);
			}
		}
	}
}

interface Condition{
	public boolean test(Person p);
}

Rather than the method(printLastNameBeginningWithC) itself containing explicitly what needs to be done. Putting this into a condition object & passing the implementation of Condition object to the method(printConditionally). You can pass different Condition implementation to the same printConditionally method & have it print different stuffs. printConditionally method just cares about printing of Person objects. The logic of what to print is inside the implementation of Condition object. Now let’s see the beauty with JAVA 8 lambdas. With JAVA 8 you can skip the complex implementation using lambdas.

public class ExerciseSolutionJava8 {

	public static void main(String[] args) {
		List<Person> people=Arrays.asList(
				new Person("Charles","Dickens",60),
				new Person("Lewis","Carroll",42),
				new Person("Thomas","Carlyle",51),
				new Person("Charlotte","Bronte",45),
				new Person("Matthew","Arnold",39));
		
		//Step 1: Sort list by last name
		Collections.sort(people, (p1,p2)->p1.getLastName().compareTo(p2.getLastName()));
		
		//Step 2: Create a method that prints all elements in the list
		printAll(people);
		
		//Step 3: Create a method that prints all people that have lastName beginning with C
		printConditionally(people, p->p.getLastName().startsWith("C"));
		
		printConditionally(people, p->p.getFirstName().startsWith("C"));
	}
	
	private static void printConditionally(List<Person> people, Condition condition) {
		for(Person p: people){
			if(condition.test(p)){
				System.out.println(p);
			}
		}
	}

	private static void printAll(List<Person> people) {
		for(Person p: people){
			System.out.println(p);
		}
	}
}

interface Condition{
	public boolean test(Person p);
}

Comparator interface has only one abstract method, so it’s a Functional Interface. So you can pass lambda instead of inline anonymous inner class. In Collections.sort() method, the type of p1 and p2 objects are automatically detected by the compiler(Type inference). Our Condition interface also has one abstract method, so we can use lambda here also. Now, we can also remove printAll method as it is same as printConditionally method with condition always true. Final rewrite.

public class ExerciseSolutionJava8 {

	public static void main(String[] args) {
		List<Person> people=Arrays.asList(
				new Person("Charles","Dickens",60),
				new Person("Lewis","Carroll",42),
				new Person("Thomas","Carlyle",51),
				new Person("Charlotte","Bronte",45),
				new Person("Matthew","Arnold",39));
		
		//Step 1: Sort list by last name
		Collections.sort(people, (p1,p2)->p1.getLastName().compareTo(p2.getLastName()));
		
		//Step 2: Create a method that prints all elements in the list
		printConditionally(people, p->true);
		
		//Step 3: Create a method that prints all people that have lastName beginning with C
		printConditionally(people, p->p.getLastName().startsWith("C"));
		
		printConditionally(people, p->p.getFirstName().startsWith("C"));
	}
	
	private static void printConditionally(List<Person> people, Condition condition) {
		for(Person p: people){
			if(condition.test(p)){
				System.out.println(p);
			}
		}
	}
}

Very crisp and not complex as it was due to anonymous inner class. Use lambdas where Functional interface(must have only one abstract method) is acceptable.

About Anoop Kumar Rai