Reputation: 79
I am using Collections.sort to sort a list in ascending order based on time field. Below is the code
private String getShipmentInpickingTime(List<Shipments> shipments) {
logger.info("in getShipmentInpickingTime");
DateFormat sdf = new SimpleDateFormat("hh:mm");
Collections.sort(shipments, (o1, o2) -> {
try {
if ((!"null".equals(o1.getShipmentinpickingtime())
&& !StringUtils.isEmpty(o1.getShipmentinpickingtime()))
&& (!"null".equals(o2.getShipmentinpickingtime())
&& !StringUtils.isEmpty(o2.getShipmentinpickingtime()))) {
return sdf.parse(o1.getShipmentinpickingtime()).compareTo(sdf.parse(o2.getShipmentinpickingtime()));
}
} catch (ParseException e) {
e.printStackTrace();
}
int count1 = 0;
return count1;
});
This method throws exception --
java.lang.IllegalArgumentException: Comparison method violates its general contract.
I went through the google regarding this issue- It says i am comparing bigger object to smaller object. I tried reversing the sequence of object, but no luck.
Upvotes: 0
Views: 915
Reputation: 857
You did not mention which line of code throws this error. I am not sure which StringUtils you used here, com.sun.deploy.util.StringUtils
does not have .isEmpty()
method. So I reimplemented it.
Here is a working code for your problem:
public static void main(String[] args){
getShipmentInpickingTime(new ArrayList<Shipments>(){{
add(new Shipments("12:00"));
add(new Shipments("12:03"));
add(new Shipments("12:02"));
}});
}
private static void getShipmentInpickingTime(List<Shipments> shipments) {
DateFormat sdf = new SimpleDateFormat("hh:mm");
System.out.println(shipments.toString());
Collections.sort(shipments, (o1, o2) -> {
try {
if ((!"null".equals(o1.getShipmentPickingTime())
&& !(o1.getShipmentPickingTime() == null || o1.getShipmentPickingTime().length() < 1))
&& (!"null".equals(o2.getShipmentPickingTime())
&& !(o2.getShipmentPickingTime() == null || o2.getShipmentPickingTime().length() < 1))) {
return sdf.parse(o1.getShipmentPickingTime()).compareTo(sdf.parse(o2.getShipmentPickingTime()));
}
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
});
System.out.println(shipments.toString());
}
Shipments class content:
public class Shipments {
private String shipmentPickingTime;
public Shipments(String shipmentPickingTime) {
this.shipmentPickingTime = shipmentPickingTime;
}
public String getShipmentPickingTime() {
return shipmentPickingTime;
}
public void setShipmentPickingTime(String shipmentPickingTime) {
this.shipmentPickingTime = shipmentPickingTime;
}
@Override
public String toString() {
return "Shipments{" +
"shipmentPickingTime='" + shipmentPickingTime + '\'' +
'}';
}
}
Output:
[Shipments{shipmentPickingTime='12:00'}, Shipments{shipmentPickingTime='12:03'}, Shipments{shipmentPickingTime='12:02'}]
[Shipments{shipmentPickingTime='12:00'}, Shipments{shipmentPickingTime='12:02'}, Shipments{shipmentPickingTime='12:03'}]
Upvotes: 0
Reputation: 311798
You catch the exception only once if either of the elements fail to parse.
Consider three shipments with the following times:
A - 12:34
B - 34:56
C - null
With your comparator, compare(A, C)
will return 0, compare(B, C)
will return 0, but compare(A, B)
will return a non-zero result, thus violating the general contract of transitivity.
One easy approach is to use the Comparator.comparing
syntax to parse each element separately:
DateFormat sdf = new SimpleDateFormat("hh:mm");
shipments.sort(Comparator.comparing(
Shipments::getShipmentinpickingtime,
Comparator.nullsLast(Comparator.comparing(time -> {
try {
if (!"null".equals(time) && !StringUtils.isEmpty(time)) {
return sdf.parse(time);
}
} catch (ParseException ignoe) {
// Not a valid time
}
return null;
})))
);
Upvotes: 1