Sort ArrayList by Date in Java - java

I'm trying to sort a list of Product objects by their useby Dates, but some of the objects may have their Date useby = null
What I want to do is sort the list by "useby" Dates, and put all the Objects that has Date useby = null on the bottom or on the top of the list.
public static void sort() {
Collections.sort(list, new Comparator<Product>() {
public int compare(Product o1, Product o2) {
if (o1.getUseDate() == null || o2.getUseDate() == null) {
return 0;
} else {
return o1.getUseDate().compareTo(o2.getUseDate());
}
}
});
}
This is my code and I don't know how to fix this.

if (o1.getUseDate() == null || o2.getUseDate() == null). Here you are checking if either of the two Product's has a null date. If even one of them does the return result of 0 means that the Comparator will see them as equal. Even if just one of them has a null date. Here you probably want to do some more in-depth checking. The following code will result in Product's with null Dates being put at the start.
if(o1.getUseDate() == null && o2.getUseDate() == null)
return 0; //They are both null, both equal
if(o1.getUseDate() == null && o2.getUseDate() != null)
return -1; // The first is null and the second is not, return the first as lower than the second
if(o1.getUseDate() != null && o2.getUseDate() == null)
return 1; //The first is not null and the second is, return the first as higher than the second
else
return o1.getUseDate().compare(o2.getUseDate()); //Return the actual comparison
This is obviously a little verbose, but it should give you an idea as to what you should actually be looking for.

return 0; means that compared elements are equal (in other words you shouldn't swap them).
In case of nulls consider
returning 0 if both values are null (first value is same as second value - don't swap)
returning -1 if first value is null but second is not null (first element is lesser than second - don't swap)
returning 1 if second value is null and first is not null (first element is greater than second - swap them)

From compare javadoc:
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.
But from this line of your code:
if (o1.getUseDate() == null || o2.getUseDate() == null) {
return 0;
we can see that you're practically telling the comparator to consider useDates as being equal when at least one of them is null, and this is not what you want.
Since null means "nothing", it's quite weird to compare the concept of nothing with a date, but if you want to allow null values, then you have to handle this situation properly, resulting into a more vorbose code:
if(o1.getUseDate() == null){
return o2.getUseDate() == null ? 0 : -1; //or +1 if you want null values at the bottom of your list
}
if(o2.getUseDate() == null){
return o1.getUseDate() == null ? 0 : -1; // or +1 ...
}
return o1.getUseDate().compare(o2.getUseDate()); // 2 non null dates, do a real comparison

Related

Why null check is necessary in the below code?

public boolean isValidCardDetails(CardDetailsTypeBean cardDetailsTypeBean) throws EnrollmentReqInvalidException {
if (cardDetailsTypeBean.getCardNumber() == null || "".equals(cardDetailsTypeBean.getCardNumber())) {
throw new EnrollmentReqInvalidException("ECDOO16", "card no is mandatory");
}
if (cardDetailsTypeBean.getNameOnCard() == null || "".equals(cardDetailsTypeBean.getNameOnCard())) {
throw new EnrollmentReqInvalidException("ECDOO17", "name on card is mandatory");
}
if (cardDetailsTypeBean.getCvv() == 0 || "".equals(String.valueOf(cardDetailsTypeBean.getCvv()))) {
throw new EnrollmentReqInvalidException("ECDOO18", "cvv is mandatory");
}
if (cardDetailsTypeBean.getExpDate() == null || "".equals(cardDetailsTypeBean.getExpDate())) {
throw new EnrollmentReqInvalidException("ECDOO19", "exp date must be required");
}
return false;
}
Well here i want to ask after getting card number and checking null,why we use "".equals there..?? can anyone explain me this? little confused?
This line of code:
cardDetailsTypeBean.getCardNumber() == null || "".equals(cardDetailsTypeBean.getCardNumber())
simply verifies if cardNumber is null or if is equal to the empty string. Empty string is different from null value, so this code checks if every field read by a getter returns a non-empty, non-null value.
It's superfluous, actually.
The reason for this is that the order of the equals statement on the other side of the logical comparison is guaranteed not to produce a NullPointerException, since String.equals(null) is engineered to produce false.
The reason it likely exists the way it does is that it's being made explicit that the code is checking for null and an empty string.
"" isn't the same as null because "" is a String value. Your card number might instantiated with ""
null means the reference of card number has no value.

Android custom sorting using comparable

I have a little problem with this snippet of code:
#Override
public int compareTo(EventResponse o) {
int compare1 = startTime.compareTo(o.startTime);
if (compare1 == 0 && o.myProviderId != null && o.providerId != null) {
return o.providerId.compareTo(o.myProviderId) != 0 ? -1 : 0;
} else {
return compare1;
}
}
I have EventResponse class which i have created that implements Comparable interface, o.myProviderId is ID of currently signed in user (into application) and o.providerId is ID of user that is assigned to particular object (EventResponse).
What I need to achieve is if there are two objects with the same startTime to show objects assigned to me first and then objects assigned to some other provider/s.
This code snippet should (and I think it did in the past) do the trick but I get error message stating: "Comparison method violates its general contract".
Please help!
The violation of the contract often means that the comparator is not providing the correct or consistent value when comparing objects.
For example :
if (compare1 == 0 && o.myProviderId != null && o.providerId != null) {
return o.providerId.compareTo(o.myProviderId) != 0 ? -1 : 0;
}
So, what happens when o.providerId.compareTo(o.myProviderId) gives you 1 or -1. In both scenario you are going to return -1 isn't it ?
Instead, why not simply return what gets return from compareTo ?
if (compare1 == 0 && o.myProviderId != null && o.providerId != null) {
return o.providerId.compareTo(o.myProviderId);
}

Comparision method violates its general contract exception

I have check why this exception occurs. Could you please guide me? What I am doing wrong in below code block?
Collections.sort(discountGroupDetailList, new Comparator<DiscountGroupDetail>() {
long bdsIdOne;
long bdsIdTwo;
public int compare(DiscountGroupDetail discountGroupDetailOne, DiscountGroupDetail discountGroupDetailTwo) {
boolean discOne;
boolean discTwo;
SimpleDateFormat DATE_FORMATER = new SimpleDateFormat("yyyy/MM/dd");
int compVal = 0;
discOne = discountGroupDetailOne != null && discountGroupDetailOne.getServiceId() != null
&& discountGroupDetailOne.getServiceId().getCodeAndVersion() != null
&& discountGroupDetailOne.getServiceId().getCodeAndVersion().getCodeDetail() != null
&& discountGroupDetailOne.getServiceId().getCodeAndVersion().getCodeDetail().getCode() != null;
discTwo = discountGroupDetailTwo != null && discountGroupDetailTwo.getServiceId() != null
&& discountGroupDetailTwo.getServiceId().getCodeAndVersion() != null
&& discountGroupDetailTwo.getServiceId().getCodeAndVersion().getCodeDetail() != null
&& discountGroupDetailTwo.getServiceId().getCodeAndVersion().getCodeDetail().getCode() != null;
if (discOne == true && discTwo == true) {
bdsIdOne = MessageBuilderHelper.getBaseDiscountServiceById(discountGroupDetailOne.getServiceId())
.getBdsIdNbr();
bdsIdTwo = MessageBuilderHelper.getBaseDiscountServiceById(discountGroupDetailTwo.getServiceId())
.getBdsIdNbr();
compVal = (int) (bdsIdOne - bdsIdTwo);
}
DateRange dateRangeOne = discountGroupDetailOne != null ? discountGroupDetailOne.getDateSegment() : null;
DateRange dateRangeTwo = discountGroupDetailTwo != null ? discountGroupDetailTwo.getDateSegment() : null;
if (compVal == 0 && dateRangeOne != null && dateRangeTwo != null) {
Date date = new Date();
compVal = DATE_FORMATER.format(date.parse(dateRangeOne.getStartDate())).compareTo(
DATE_FORMATER.format(date.parse(dateRangeTwo.getStartDate())));
}
DiscountCode discountTypeOne = (discountGroupDetailOne != null && discountGroupDetailOne
.getVolumeDiscountGroupDetail() != null) ? DiscountCode.getDiscount(discountGroupDetailOne
.getVolumeDiscountGroupDetail().getType()) : null;
DiscountCode discountTypeTwo = (discountGroupDetailTwo != null && discountGroupDetailTwo
.getVolumeDiscountGroupDetail() != null) ? DiscountCode.getDiscount(discountGroupDetailTwo
.getVolumeDiscountGroupDetail().getType()) : null;
boolean isFXG = ("FXG".equals(discountGroupDetailOne.getServiceGeography()) || (discountGroupDetailOne
.getServiceId() != null && "FXG".equals(discountGroupDetailOne.getServiceId().getOperatingCompany())))
&& ("FXG".equals(discountGroupDetailTwo.getServiceGeography()) || (discountGroupDetailTwo
.getServiceId() != null && "FXG".equals(discountGroupDetailTwo.getServiceId()
.getOperatingCompany())));
if (compVal == 0 && discountTypeOne != null && discountTypeTwo != null && isFXG) {
compVal = ((int) (Integer.parseInt(discountTypeOne.getDiscountID()) - Integer.parseInt(discountTypeTwo
.getDiscountID())));
}
return compVal;
}
});
}
#immibis spotted the answer before I could. To generalize the principle: Say you're writing a comparator that compares multiple pairs of keys. You want to compare the first pair, and then if that doesn't give you a < or > answer, compare the second pair, and if you still don't have < or >, compare the third pair, and so on.
The rule here is that after comparing the first pair, you may not go on to the second pair unless the keys in the first pair are equal. In your case, they're equal if both have a "code" and the codes are equal, or if they're both null. Your mistake is that you go on to the next pair if only one code is null. They're not equal in that case. I guess your thinking is that you can't compare the codes if one item doesn't have a code. But you must. You need to decree that an item with no code is less than an item with a code (or greater than; it depends on how you want to see them in your sorted array); and you have to check for that, and return (for instance) a negative number if the left item has a null code, and a positive number if the right item has a null code.
Then you need to do the same with the date range; if one argument has a date range and the other doesn't, they are not equal and you must return a negative or positive number, instead of proceeding to the third key.
This is almost always caused by your comparator either not being transitive or not being asymmetric. For transitivity, given three DiscountGroupDetail objects a, b, and c, if a precedes b and b precedes c, then the general contract requires that a precede c in all cases. Likewise, if a equals b and b equals c, then it is required that a equals c. For asymmetry, swapping the comparison order for two objects a and b that do not return 0 must return a number of the opposite sign.
Given your complex logic, it's difficult for me to determine exactly where things are going wrong, but the above is what you need to check.

Validating BigDecimal data type for nulls In Java

I am trying to validate for NULLs on a data type BigDecimal in java. I am able to validate for 0 value however NULL's is resulting in a NULL Point Exception. Should I handle the validation of this datatype in an exception or is there some calculation I can preform on the data to validate it. Under is an example of what i have done so far:
if(crime.getCrimeLatLocation() != null & crime.getCrimeLongLocation() != null || crime.getCrimeLatLocation().compareTo(BigDecimal.ZERO) != 0 & crime.getCrimeLongLocation().compareTo(BigDecimal.ZERO) != 0){
logger.info('Valid Data');
}
Your || should be an && - what's happening is that when you pass in a null value it's evaluating to false in the first two conditions, but then it's proceeding on to the third and fourth conditions and resulting in an exception. If you change the || to an && then short circuit evaluation will prevent the third and fourth conditions from evaluating.
Be certain to use a && and not a & - the former uses short-circuit evaluation, but the latter would force the third and fourth conditions to evaluate and you'll get a null pointer exception again. condition1 && condition2 says "return false if condition1 is false, else evaluate condition2" - if condition1 is false then condition2 is never evaluated. In contrast, condition1 & condition2 will always evaluate both conditions. The only reason to use & is if the conditions have side-effects. Likewise, condition1 || condition2 will not evaluate condition2 if condition1 is true, but | will always evaluate both conditions.
Your test here
if(crime.getCrimeLatLocation() != null & crime.getCrimeLongLocation() != null
|| crime.getCrimeLatLocation().compareTo(BigDecimal.ZERO) != 0 & crime.getCrimeLongLocation().compareTo(BigDecimal.ZERO) != 0)
Uses binary not boolean operators, change this to
if((crime.getCrimeLatLocation() != null && crime.getCrimeLatLocation().compareTo(BigDecimal.ZERO) != 0)
|| (crime.getCrimeLongLocation() != null && crime.getCrimeLongLocation().compareTo(BigDecimal.ZERO) != 0))
This says that either crimeLatLocation is not null and not zero or crimeLongLocation is not null and not zero.
When you use & then both sides of the expression are evaluated, when you use && then the test is short circuited if the first part of the expression is false.
You need a check for null values before the comparison. You may use this function for the comparison.
/** This method compares 2 BigDecimal objects for equality. It takes care of null object and that was the necessity of having it.
* To use this function most efficiently pass the possibly null object before the not null object.
* #param pNumber1
* #param pNumber2
* #return boolean
*/
public static boolean isEqual(BigDecimal pNumber1, BigDecimal pNumber2)
{
if ( pNumber1 == null )
{
if ( pNumber2 == null)
return true;
return false;
}
if ( pNumber2 == null)
return false;
return pNumber1.compareTo(pNumber2)==0;
}
If your main goal is validating BigDecimal dataType for nulls, then just make a comparison;
yourBigDecimal != null.
The above statement is enough for comparison and checking.

If a LinkedList is empty, return nothing from a method that returns an int?

EDIT: Solved. Returning a 0 works, apparently!
Ok so long story short, I have to return an int value, but nothing when a Linked List is empty. How do I do it?
public int countDuplicates() {
int duplicates = 0;
ListNode current = front;
int num = current.data;
current = current.next;
while(current != null) {
if(current.data == num) {
duplicates++;
} else {
num = current.data;
}
current = current.next;
}
return duplicates;
}
When I try this:
if(front == null) {
return ;
}
This doesn't work. What can I do?
You can rather throw an IllegalArgumentException: -
if(front == null) {
throw new IllegalArgumentException("List is empty");
}
If your method returns an int you must determine an acceptable value to represent "nothing". Such as 0 or if valid results are >= 0, use a negative value such as -1 to indicate "nothing".
Alternatively, modify your method to return an Integer object in which case you can return null.
It is possible for you to either define a fixed value, such as Integer.MIN_VALUE, that would indicate that the list is empty, or change the declaration of your method to public Integer countDuplicates(), and return null when the list is empty.
To keep the code as you have it now, you must either return an int, throw an exception, or exit.
Return an int: You'll have to specify a certain int value as the "fail" value and make sure that it is never the case that this value is hit during "normal" execution.
Throw an exception: Detailed in another answer - you've already shot it down.
Exit the program... if it makes sense to do that.
The best option may be to change the code - make the function return an Integer, for example, so the null option is there. There are surely other ways to work around it, as well.
you can change the return value from int to object like this
public Object countDuplicates() {
if(////condition)
return ///int;
else
return null;
You could return a negative value or change the return type to string and parse the result to int.
If you don't want to (or can't) throw an exception, return some "exceptional value", such as a negative number. For example, Java has a lot of indexOf(Object somethingToLookFor) methods that return a -1 if the item isn't found.
In your example, -1 works as exceptional because there can never be -1 duplicates.
Personally, I would just return 0 for an empty List. An empty list has 0 duplicates. But if the spec insists on something exceptional, return -1.
public boolean isEmpty(){
if (head == null) return true;
else return false ;
}

Categories