Reputation: 3457
Incase the Field is empty , how can i sort the list based on Date ?
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
class Person implements Comparable < Person > {
private String name;
private String birthdate;
public Person(String name, String birthdate) {
this.name = name;
this.birthdate = birthdate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirthdate() {
return birthdate;
}
public void setBirthdate(String birthdate) {
this.birthdate = birthdate;
}
@Override
public int compareTo(Person otherPerson) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
LocalDate currentPersonDate = LocalDate.parse(birthdate, formatter);
LocalDate otherPersonDate = LocalDate.parse(otherPerson.getBirthdate(), formatter);
int retVal = otherPersonDate.compareTo(currentPersonDate); // 1 Comparing With Dates DESC
return retVal;
}
}
// 2009-06-23 00:00:00.0
public class TestClient {
public static void main(String args[]) {
ArrayList < Person > personList = new ArrayList < Person > ();
Person p1 = new Person("Shiva ", "2020-09-30 00:00:00.0");
Person p2 = new Person("pole", "2020-09-30 00:00:00.0");
Person p3 = new Person("Balal ", "");
personList.add(p1);
personList.add(p2);
personList.add(p3);
Collections.sort(personList);
System.out.println("After Descending sort");
for(Person person: personList){
System.out.println(person.getName() + " " + person.getBirthdate());
}
}
}
I have handled code as shown below using Java 8
@Override
public int compareTo(Person other) {
try
{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
return Comparator.comparing((Person student) -> LocalDate.parse(student.getBirthdate(), formatter)).reversed()
.compare(this, other);
}
catch(Exception e)
{
}
return -1;
}
But how to make all nulls and empty appear in top
Upvotes: 0
Views: 103
Reputation: 4952
First of all, don't parse the date in your compareTo()
method. That slows down the CompareTo method, which slows down any sorting you'll do. Put the parsed date in a field, and set its value in your setter:
private static final DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
private LocalDate localBirthday = null;
public void setBirthdate(String birthdate) {
this.birthdate = birthdate;
localBirthday = ((birthdate == null) || birthdate.isEmpty()) ?
null : LocalDate.parse(birthdate, formatter);
}
And call this setter in your constructor to make sure it always gets set:
public Person(String name, String birthdate) {
this.name = name;
setBirthdate(birthdate);
}
(It's probably a better idea to get rid of the String field and require the user to provide a LocalDate instead. You can still use your formatter for printing. Also, the way you're formatting your dates, they can be sorted as Strings and still get the right order, but you'd still need a formatter to guarantee the correct format.)
Now you're ready to write your compareTo()
method. The way to handle nulls is to decide where nulls should fall in the order, and write a compareTo()
method that enforces that order, like this, which puts nulls first:
@Override
public int compareTo(Person that) {
if (this == that) {
return 0;
}
// If we need to worry about "that" Person being null, this puts nulls first:
if (that == null) {
return 1;
}
// In a Comparator, we would worry about both Persons being null. But in a
// Comparable, one of them is "this," which is never null.
// Now we work on the localBirthday. We know that neither this nor that is
// null. I'm assuming that we're only sorting by birthday, so we don't look at
// the name field.
if (Objects.equals(this.localBirthday, that.localBirthday)) {
return 0;
}
if (this.localBirthday == null) {
return -1;
}
if (that.localBirthday == null) {
return 1;
}
return this.localBirthday.compareTo(that.localBirthday);
}
But that was just to illustrate the general principle. In Java 7 and 8, there are tools to make this easier. But first, we need a getter for the added LocalDate
field.
public LocalDate getLocalBirthdate() { return localBirthday; }
// You need an equals() method that's consistent with your compareTo() method
@Override
public boolean equals(Object other) {
if (!(other instanceof Person)) { // implicit null test, too.
return false;
}
Person that = (Person) other;
return Objects.equals(this.localBirthday, that.localBirthday);
}
@Override
public int compareTo(Person that) {
// This assumes you've written an equals() method that's consistent
// with this compareTo() method, above.
if (Objects.equals(this, that)) {
return 0;
}
// Put nulls first:
if (that == null) {
return -1;
}
return Comparator.comparing(Person::getLocalBirthdate,
Comparator.nullsFirst(Comparator.naturalOrder())).compare(this, that);
}
To unpack that return statement, here's how it works.
First, the comparing()
method takes a function pointer, then a Comparator. The comparator will work on the return value from the function you specified. I chose Comparator.nullsFirst(T)
as the comparator, because it first handles null values before deferring to T. For T, I chose Comparable.naturalOrder()
which compares objects by their natural order. This means it calls the LocalDate's compareTo()
method when neither date is null.
Two more quick notes: You might want to remove the time of day from your formatter and your test data. And you also need a hashCode()
method that's consistent with equals()
.
Upvotes: 0
Reputation: 40078
You can use try-catch
for catching the exception and return some value either -1
,0
or 1
depending on sorting order in case of exception
try {
LocalDate currentPersonDate = LocalDate.parse(birthdate, formatter);
LocalDate otherPersonDate = LocalDate.parse(otherPerson.getBirthdate(), formatter);
return otherPersonDate.compareTo(currentPersonDate);
}catch(Exception ex) {
//log error
}
return -1;
Upvotes: 1