I have been asked a question in interview where the requirement was to sort a list of Person using JAVA streams and comparator.
Given that, we have list of persons and multiple sort parameters in the input/ Sort parameters will be holding list of attribute name like personFirstName, personLastName and personAge.
I have written following program where I tried to create a composition of Comparator using "thenComparing" method but it did not work.
package com.sample.streams.composition;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class StreamComposition {
class Person {
private String personFirstName;
private String personAge;
private String personLastName;
public Person(String personFirstName, String personAge, String personLastName) {
super();
this.personFirstName = personFirstName;
this.personAge = personAge;
this.personLastName = personLastName;
}
@Override
public String toString() {
return "PersonFirstName : [" + personFirstName + "], PersonLastName : [" + personLastName
+ "], PersonAge : [" + personAge + "]";
}
public String getPersonFirstName() {
return personFirstName;
}
public void setPersonFirstName(String personFirstName) {
this.personFirstName = personFirstName;
}
public String getPersonAge() {
return personAge;
}
public void setPersonAge(String personAge) {
this.personAge = personAge;
}
public String getPersonLastName() {
return personLastName;
}
public void setPersonLastName(String personLastName) {
this.personLastName = personLastName;
}
}
public static void main(String[] args) {
StreamComposition ob = new StreamComposition();
Person p1 = ob.new Person("Gunjan", "30", "Shah");
Person p2 = ob.new Person("Vimal", "36", "Panchal");
Person p3 = ob.new Person("Pooja", "29", "Wadkar");
Person p4 = ob.new Person("Pooja", "55", "Thomas");
List<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
System.out.println("------------CASE 1----------------");
List<String> sortBy = new ArrayList<>();
sortBy.add("personFirstName");
sortAndPrint_1(list, sortBy);
sortAndPrint_2(list, sortBy);
System.out.println("------------CASE 2----------------");
sortBy.add("personAge");
sortAndPrint_1(list, sortBy);
sortAndPrint_2(list, sortBy);
System.out.println("------------CASE 3----------------");
sortBy.add("personLastName");
sortAndPrint_1(list, sortBy);
sortAndPrint_2(list, sortBy);
}
public static void sortAndPrint_1(List<Person> persons, List<String> sortBy) {
System.out.println("Method : sortAndPrint_1");
List sortedPersons = (List) persons
.stream()
.sorted(
sortBy
.stream()
.map( s -> Comparator.comparing(getFunction(s)))
.reduce((c1,c2) -> c1.thenComparing(c2))
.get())
.collect( Collectors.toList());
sortedPersons
.stream()
.forEach( p -> System.out.println(p));
}
public static void sortAndPrint_2(List<Person> persons, List<String> sortBy) {
System.out.println("Method : sortAndPrint_2");
sortBy
.stream()
.map( s -> Comparator.comparing(getFunction(s)))
.forEach(c -> Collections.sort(persons,c));
persons
.stream()
.forEach( p -> System.out.println(p));
}
public static Function getFunction(String param) {
Function<Person,String> function = null;
switch (param) {
case "personFirstName" :
function = (p) -> p.getPersonFirstName();
break;
case "personLastName" :
function = (p) -> p.getPersonLastName();
break;
case "personAge" :
function = (p) -> p.getPersonAge();
break;
}
return function;
}
}
And the output of above program is as below :
------------CASE 1----------------
Method : sortAndPrint_1
PersonFirstName : [Gunjan], PersonLastName : [Shah], PersonAge : [30]
PersonFirstName : [Pooja], PersonLastName : [Wadkar], PersonAge : [29]
PersonFirstName : [Pooja], PersonLastName : [Thomas], PersonAge : [55]
PersonFirstName : [Vimal], PersonLastName : [Panchal], PersonAge : [36]
Method : sortAndPrint_2
PersonFirstName : [Gunjan], PersonLastName : [Shah], PersonAge : [30]
PersonFirstName : [Pooja], PersonLastName : [Wadkar], PersonAge : [29]
PersonFirstName : [Pooja], PersonLastName : [Thomas], PersonAge : [55]
PersonFirstName : [Vimal], PersonLastName : [Panchal], PersonAge : [36]
------------CASE 2----------------
Method : sortAndPrint_1
PersonFirstName : [Gunjan], PersonLastName : [Shah], PersonAge : [30]
PersonFirstName : [Pooja], PersonLastName : [Wadkar], PersonAge : [29]
PersonFirstName : [Pooja], PersonLastName : [Thomas], PersonAge : [55]
PersonFirstName : [Vimal], PersonLastName : [Panchal], PersonAge : [36]
Method : sortAndPrint_2
PersonFirstName : [Pooja], PersonLastName : [Wadkar], PersonAge : [29]
PersonFirstName : [Gunjan], PersonLastName : [Shah], PersonAge : [30]
PersonFirstName : [Vimal], PersonLastName : [Panchal], PersonAge : [36]
PersonFirstName : [Pooja], PersonLastName : [Thomas], PersonAge : [55]
------------CASE 3----------------
Method : sortAndPrint_1
PersonFirstName : [Gunjan], PersonLastName : [Shah], PersonAge : [30]
PersonFirstName : [Pooja], PersonLastName : [Wadkar], PersonAge : [29]
PersonFirstName : [Pooja], PersonLastName : [Thomas], PersonAge : [55]
PersonFirstName : [Vimal], PersonLastName : [Panchal], PersonAge : [36]
Method : sortAndPrint_2
PersonFirstName : [Vimal], PersonLastName : [Panchal], PersonAge : [36]
PersonFirstName : [Gunjan], PersonLastName : [Shah], PersonAge : [30]
PersonFirstName : [Pooja], PersonLastName : [Thomas], PersonAge : [55]
PersonFirstName : [Pooja], PersonLastName : [Wadkar], PersonAge : [29]
Here, I have created two methods sortAndPrint_1 and sortAndPrint_2. In method sortAndPrint_1, I have first created outer stream over person list and then I am trying to apply composition of comparators but it is not working.
So, I wrote another method sortAndPrint_2 where I am iterating over outer stream of sortBy and using Collection.sort method to sort the list. This method is sorting the records as expected after adding missing break statements in switch case.
Here, the aim of the program is to achieve multi level sorting.
I am still facing issues with method "sortAndPrint_1" which generates wrong output. I want the record first sorted on peronFirstName, then on personAge, then on personLastName.
Can someone please suggest me what is wrong with logic of "sortAndPrint_1" ? Is there any problem with the way I have used reduce method ?