Android custom sorting using comparable - java

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);
}

Related

Check which combinations of parameters are null in Java

I am new to Java. I am facing an issue now in which I couldn't find the easiest and cleanest way of solving it.
Suppose I have 3 parameters(string) passed to a function(could be a Hashmap too).I want to check if individual variable or combination of variables is not Null and act accordingly.
For example one way to do this is using if-else this way
if(a!=null && b == null && c == null) {
//doSomething
}
else if(a==null && b!= null && c == null ) {
//doSomething
}
else if(a==null && b0= null && c != null) {
//doSomething
}
......
//Similarly combination of two variables
if(a!=null && b != null && c == null) {
//doSomething
}
else if(a!=null && b== null && c != null) {
//doSomething
}
else if(a==null && b!= null && c != null) {
//doSomething
}
......
//and so on
//Similarly combination of three variables
if(a!=null && b != null && c != null) {
//doSomething
}
....
How to achieve this kind of situation. I found similar question, but didn't make the code clean. Any help will be appreciated
Write these utility functions and you can compare n terms easily.
public static boolean areAllNull(Object... objects) {
return Stream.of(objects).allMatch(Objects::isNull);
}
public static boolean areAllNotNull(Object... objects) {
return Stream.of(objects).allMatch(Objects::nonNull);
}
you can use these functions for n comparisons.
if(areAllNotNull(a) && areAllNull(b,c)) {
//doSomething
}
else if(areAllNotNull(b) && areAllNull(a,c)) {
//doSomething
}
else if(areAllNotNull(c) && areAllNull(b,a)) {
//doSomething
}
This is my solution. Note, that you have multiple if...else in one single method. And then you add doSomething. This is going to be terrible to ready and later to realize.
What about to move one single condition into separate method and name it with relative name. Then, lets encapsulate it into Consumer and all of it into a predefined list. Later, if your doSomething will be huge, then you can move from single method to single class, not modifying client code.
This is class, to collect required variable for conditions:
final class Data {
private final String a;
private final String b;
private final String c;
}
Then define one Consumer per on if statement:
Consumer<Data> wonderfulConsumer = data -> {
if (a != null && b == null && c == null) {
// do something for wonderful consumer
}
};
Consumer<Data> badLuckConsumer = data -> {
if (a == null && b != null && c == null) {
// do something for bad luck consumer
}
};
Note, all these consumers could be modified separately (even be in the different classes).
Then in the client code, define list of all known consumers: List<Consumer<Data>> consumers = Arrays.asList(wonderfulConsumer, badLuckConsumer).
And finally your method will be like this and you do not need to change it when you decide to modify or add consumers.
Data data = new Data(a, b, c);
consumers.forEach(consumer -> consumer.accept(data));
If I had to do this , i will do it in the same way that you have done.
but if you dont like that and if you think it is not readable you can do it in this way, i expect lot of negative comments to this answer because this is a bad solution.
public static void yourMethod(Object a,Object b,Object c)
{
int evaluation = howManyNotNull(a,b,c);
if(evaluation == 0) // all are nulls
{
// your code
}
else if(evaluation == 1) // only one is not null
{
if(a!=null)
{
}
else if(b!=null)
{
}
else
{
// c not null
}
}
else if(evaluation == 2) // two variables are not null but other one is null
{
if(a==null)
{
}
else if(b == null)
{
}
else
{
// c is null, a and b not null
}
}
else
{
// all abc not null
}
}
private static int howManyNotNull(Object a, Object b, Object c)
{
return (a==null?0:1) + (b==null?0:1) + (c==null?0:1);
}
There is extended version of this , assign 3 prime values for a, b , c (example :a=2,b=3,c=5), then use a supportive method like this
private static int convertAvailabilityToInt(Object a, Object b, Object c)
{
return (a==null?1:2) * (b==null?1:3) * (c==null?1:5);
}
if the answer is 1 ,then all are not null .
You can use for example a 3 digit string simulating 3 flags.
You first set it to "000".
Then you check each variable for null, if it is not you will replace the 0 with 1.
Then you could use switch cases to treat each case.
You are doing everything right but you have to remember that primitive data types cannot be null. For example string is not null, but empty string "", or int cannot be null, its by default sets to 0. In conclusion Objects like Map , ArrayList or Integer.. you can check for null, but primitive data types cannot be null, so you cannot check them for it. For deeper understanding just learn about primitive and advanced data types.
I hope I got your problem right :)

CompareTo is transitive

I have a POJO looking like this:
public class Pojo implements Comparable<Pojo> {
private String type;
private String journalId;
private Date bookingDate;
private Long account;
private String description;
private BigDecimal debit;
private BigDecimal credit;
....
}
and I want to sort a list of these POJOs. Currently my compareTo method looks like this:
#Override
public int compareTo(EfdisJournal other) {
int i = this.type.compareTo(other.type);
if (i != 0)
return i;
if (this.bookingDate != null && other.bookingDate != null)
i = this.bookingDate.compareTo(other.bookingDate);
if (i != 0)
return i;
if (this.journalId != null && other.journalId != null)
i = this.journalId.compareTo(other.journalId);
if (i != 0)
return i;
return this.account.compareTo(other.account);
}
If I run a sort with this compareTo method, I get this java.lang.IllegalArgumentException: Comparison method violates its general contract error. I did google a bit and I think it happens because some of the fields are null on comparison. Yet I have no idea how to solve this or if I am right why that error appears.
The comparison should work like this: 1st compare by type, then compare by bookingDate, as 3rd compare by journalId and at last compare by account. All comparisons should be ascending.
type is never null
bookingDate may be null
journalId may be null
account is never null
EDIT:
Sadly I was not able to implement the method, so that the order is as needed. Yet, i solved the problem I had, because the stored procedure yielded 2 resultsets, of which the second was order as needed, so the only thing I had to do was to use the 2nd resultset instead of the first.
You need to deal with the case where one instance has a null bookingDate, and the other has a non-null bookingDate.
You should decide whether things with null bookingDate should be sorted before or after things with a non-null bookingDate, and write your compareTo appropriately. (And then journalId too.) Then you can get an order that sorts consistently.
For instance:
#Override
public int compareTo(EfdisJournal other) {
int i = this.type.compareTo(other.type);
if (i != 0) {
return i;
}
if ((this.bookingDate==null) ^ (other.bookingDate==null)) {
return (this.bookingDate==null ? -1 : 1);
}
if (this.bookingDate != null && other.bookingDate != null) {
i = this.bookingDate.compareTo(other.bookingDate);
}
if (i != 0) {
return i;
}
if ((this.journalId==null) ^ (other.journalId==null)) {
return (this.journalId==null ? -1 : 1);
}
if (this.journalId != null && other.journalId != null) {
i = this.journalId.compareTo(other.journalId);
}
if (i != 0) {
return i;
}
return this.account.compareTo(other.account);
}
You're ignoring situations where bookingDate and/or journalId is null with one and non-null with the other.

How to write an recursive instance method to check whether a binary tree is structurally identical to another binary tree?

So today my data structures final had an exam question that asked this:
"Consider the BinaryTree class and add two recursive methods (independent from each other) named compBT to compare two binary trees. If the two binary trees are structurally identical (i.e., they look the same when the objects stored in the nodes are ignored), each of the two methods returns true; otherwise, each returns false. The first method should be an instance method and the second method should be a class method. Do not access the underlying data structure directly. Note: each method should not take more than 6 lines and be properly indented."
I was able to produce this for the class method:
public static boolean compareTrees(BinaryTree t1, BinaryTree t2) {
if (t1 == null && t2 == null) return true;
if ((t1 == null && t2 != null) || (t1 != null && t2 == null)) return false;
return compareTrees(t1.left, t2.left) && compareTrees(t1.right, t2.right);
}
I felt pretty confident about this answer, but writing the instance method had me totally stumped, especially since it had to be independent from the class method. All I was able to produce was the following:
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
return (compareTrees(this.left) && (t.left)) && (compareTrees(this.right) && compareTrees(t.right));
}
I know the method is incorrect since it will always return false because there is only one base case which will always be met. My thought process behind that particular base case is that if the parameter is null, then return false since there is a structural inequality because the caller cannot be null (only non-null references can call instance methods). But I didn't know what else to do from there.
Can anyone chime in? I thought this problem was pretty interesting.
Edit: adding in BinaryTree class.
Here's what the BinaryTree class looked like:
class BinaryTree {
public int value;
public BinaryTree left;
public BinaryTree right;
public BinaryTree(int x) { value = x;}
}
For instance method, all that changes is that check is before recursion, no in it:
public boolean compareTrees(BinaryTree other) {
if (left == null) != (other.left == null) return false;
if (right == null) != (other.right == null) return false;
if (left != null && !left.compareTrees(other.left)) return false;
if (right != null && !right.compareTrees(other.right)) return false;
return true;
}
I think you've recognized the basic problem. In your static method, you can pass null for both child trees when you call the method recursively. But in your instance method, you can only do that for the parameter. You can't do that for the instance method, since you can't call an instance method on null.
Well, if you can't call the instance method recursively on a null child, you have to handle the null child case before the recursive call. That's the key here, the realization that you will have to rearrange your logic. So your logic will need to be something like this:
If the parameter is null, return false (like you already did)
If the instance's left child is null, then:
2.1 If the parameter's left child is not null, return false
2.2 If the parameter's left child is null, keep going with step 4
If the instance's left child is not null, then call recursively on the left child (it doesn't matter if the parameter's left child is null, because that will be caught be #1), and return false if the recursive call returns false
4-5. Same steps for the right child
If we've gotten this far, and no check has failed, then we can return true
So the code looks something like this:
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
if (this.left == null) {
if (t.left != null) {
return false;
}
}
else if (!this.left.compareTrees(t.left)) {
return false;
}
if (this.right == null) {
if (t.right != null) {
return false;
}
}
else if (!this.right.compareTrees(t.right)) {
return false;
}
return true;
}
EDIT: I just now noticed the requirement that the method not be more than 6 lines. So I guess my answer won't work. On the other hand, I could make it work by compressing a bunch of stuff onto a few lines.
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
if (this.left == null && t.left != null) return false;
if (this.left != null && !this.left.compareTrees(t.left)) return false;
if (this.right == null && t.right != null) return false;
if (this.right != null && !this.right.compareTrees(t.right)) return false;
return true;
}
I could make it even shorter by combining the last two lines into one. But
if your professor is going to reward compressed, harder-to-read code such as this, and fail cleaner code like I had in my earlier example, shame on him.
More: OK, if your professor measures code quality by a smaller number of lines, this should make him ecstatic, even though all my colleagues would blast it in a code review:
public boolean compareTrees(BinaryTree t) {
return !((t == null) || (this.left == null && t.left != null) || (this.left != null && !this.left.compareTrees(t.left)) || (this.right == null && t.right != null) || (this.right != null && !this.right.compareTrees(t.right)) );
}

What is a shorter way of comparing Boolean objects in Java 6?

I’m using Java 6. I have two Boolean objects, a and b. How do I compare the two in terms of their value? I have come up with this, but it seems really long and messy …
(a == null && b == null) || (a != null && b != null && a.booleanValue().equals(b.booleanValue()))
I like Apache’s StringUtils.equals(a, b) method for comparing strings, but there doesn’t seem to be an equivalent method for BooleanUtils.
You can use the following for any two Objects including two Boolean
a == null ? b == null : a.equals(b);
This works for Java 1.0+
you can use the compareTo in the class boolean.. it is avaliable since 1.5
take a look to this snippet
private static int compare(Boolean a, Boolean b) {
// if (a == null || b == null) {
// return -1;
// }else {
// return a.compareTo(b);
// }
return (a == null || b == null) ? -1 : a.compareTo(b);
}
the return line is doing the same as the commented one...

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.

Categories