Java Streams 4 Q&A (Need to know about Java Q&A Article Series 7)
Hi Java people.
I am Huseyin. Have been a .Net developer for years and Java backend and Android developer for 6 years as well as a QA Automation Engineer team member for several projects for 3 years.
Have been getting a reasonable amount of questions from any level of Java developers for years. In the end, decided to write my own answers instead of spending my time over the same thing again and again. As a developer, by experiencing the reusability, abstraction and the maintainability issues for years, I decided to implement the same structure in my life and abstract myself from answering similar questions 🙂. Thus, put my effort into creating this “Need to know about Java Q&A Article Series”. By doing so, I am comfortable about answering similar questions by just sending a link to these articles 🙂. It helped me to understand many very important concepts of Java as well.
The target audience of “Need to know about Java Q&A Article Series” is the ones who already know coding with Java, but also want to improve his/her knowledge or to prepare for Java Interviews. If you are a new bee, I believe these articles may be a couple of levels higher for you.
Main purpose of these articles is not to explain topics in detail. Of course there are a lot of sources about Java on the internet. What I experienced is that some different approaches while explaining the same thing helps people to understand the topics. What I am trying to do is actually that. A different kind of explanation.
Articles are prepared by Question & Answer structure which I do believe is an efficient way of learning.
If these articles help you to understand a concept, I definitely feel very happy. Feel free to share and comment.
Sharing is learning at the same time! Enjoy.
Which interface in Java is used to sort a list of objects based on custom order?
First of all let’s analyze the Collections.sort() method.
String List sorting;
List<String> list =
new ArrayList<>(List.of(“Rangers”, “Dirty”, “Java”));Collections.sort(list);System.out.println(list);
Output; [Dirty, Java, Rangers]
Employee list sorting;
List<Employee> employees =
new ArrayList<>(List.of(new Employee(“Mike”),
new Employee(“Adam”)));
When I wanna use; Collections.sort(employees);
I got this compile time error;
The compiler says; Employee class does not implement Comparable interface. Collections.sort() method explanation;
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface.
In the first example (String List sorting) the compiler did not complain, because String class already implements Comparable interface;
Comparable interface is a Functional Interface, it only contains compareTo() method which takes generic type object as parameter;
compareTo() method explanation;
Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
Let’s look at the String class to see how it implemented compareTo() method;
To sum up, using Collections.sort() method with wrapper classes doesn’t create compile time errors since they already implemented Comparable Interface. But, when we want to use the Collections.sort() method with custom types we must implement the Comparable Interface.
The Comparable interface provides natural order like the lexicographic order of String.
To sort employee list with Comparable interface, firstly, implement it;
Then, the compiler does not complain about the Collections.sort() method usage;
Output; [Employee{name=’Adam’}, Employee{name=’Mike’}]
As you see the output; it is ordered naturally. For reverse ordering;
Collections.sort(employees, Collections.reverseOrder());
Output; [Employee{name=’Mike’}, Employee{name=’Adam’}]
Up to now, we analyzed the first approach for sorting a list of objects based on custom order.
Second approach is to implement Comparator Functional Interface. Comparator interface explanation;
A comparison function, which imposes a total ordering on some collection of objects. Comparators can be passed to a sort method (such as Collections.sort or Arrays.sort) to allow precise control over the sort order.
As it is explained, we can pass Comparator Interface implementation as an argument to sort method of List Interface;
And sort method of Collections utility class;
So, what we have in this Comparator Interface is compare() method;
Method explanation;
Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
Sorting employee list by their names applying Comparator interface implementation over sort method of List Interface;
employees.sort((o1, o2) -> o1.name.compareTo(o2.name));
Output; [Employee{name=’Adam’}, Employee{name=’Mike’}]
Sorting employee list reverse by their names applying Comparator interface implementation over sort method of Collections class;
Collections
.sort(employees, Collections
.reverseOrder((o1, o2) ->
o1.name.compareTo(o2.name)));
Output; [Employee{name=’Mike’}, Employee{name=’Adam’}]
To sum up; sorting a list of objects based on custom order can be achieved by implementing Comparator interface or Comparable interface.
Which static method in Java accepts a Function and returns a Comparator for the type which contains the sort key?
The static comparing() method of the Comparator interface accepts a function (Function Interface implementation whose apply function takes an object and returns a value by executing the implementation code). That function interface extracts a Comparable sort key from a type T, and returns a Comparator that compares by that sort key;
“Extracting sort key” means; returning a value that will be applied to sort the underlying type of list. Since the Function interface is the parameter, we are free to apply any kind of logic. For example if our aim is to sort employees by their names’ length;
List<Employee> employees =
new ArrayList<>(List.of(new Employee(“Kicchi”),
new Employee(“Mike”)));Comparator<Employee> comparator = Comparator
.comparing(employee -> employee.name.length());Collections.sort(employees, comparator);System.out.println(employees);
Output; [Employee{name=’Mike’}, Employee{name=’Kicchi’}]
Another example can be sorting the employees by their names’ characters’ ascii decimal sum;
List<Employee> employees =
new ArrayList<>(List.of(new Employee(“Kicchi”),
new Employee(“Mike”)));Comparator<Employee> comparator = Comparator
.comparing(employee -> employee.name.chars().sum());Collections.sort(employees, comparator);employees
.forEach(employee -> System.out.println(
employee.name.chars().sum()
+ “ : “ + employee));
Output;
390 : Employee{name=’Mike’}
587 : Employee{name=’Kicchi’}
So, the comparing method is much more flexible than the compare method in that it enables a developer to apply a logic for getting a new kind of sort key rather than just using the field values.
Can we chain Comparators? Give one example
Comparators can be chained. Imagine this scenario; We want to order employees by their ages, and we want to order sorted age groups by their name;
List<Employee> employees =
new ArrayList<>(List.of(new Employee(“Otto”, 18),
new Employee(“Kicchi”, 18),
new Employee(“Mike”, 50)));Comparator<Employee> sortByAge = Comparator
.comparing(Employee::getAge);Comparator<Employee> sortByName = Comparator
.comparing(Employee::getName);employees.sort(sortByAge.thenComparing(sortByName));employees.forEach(System.out::println);
Output;
Employee{name=’Kicchi’, age=18}
Employee{name=’Otto’, age=18}
Employee{name=’Mike’, age=50}
Here the ordering will be done by age, and for the values with the same age, the ordering will be done by name.
Thanks for reading. Hope this helps! See you in the next articles.
PS: Really benefited from especially Baeldung and other Java Tutorial Websites, as well as Official Java Documentation.