Home > Software design >  method erroring on Last iteration
method erroring on Last iteration

Time:12-30

Description

I have an equals method that takes in a Generic Implementation of Deque and compares it to an instance of its own Generic Implementation, comparing the two Deques.

The arrays are deemed equal if:

  • size of arrays are the same
  • they are both an 'instanceof' deque
  • they have the same values at the same indexes

Issue

However if i provide a comparison for two Deques, both with the same values and implementation, the code breaks.

Tracing the debugger brings me to the last iteration of the loop that checks all the values:

for (int i = 0; i < array.length; i  ) {
            type part1 = this.array[(head   1   i) % array.length];
            type part2 = (type) otherarr.get(i);
            if (part1 != part2) {
                return false;
            }
        }

Despite both part1 (value of index i of this.array) and part2 (value of index i of otherArr) being the same, and having no issues for all of the previous indexes, somehow the code breaks, and only for the last line.

Visual of both Deques: Visual of both deques

Full Code of Method

@Override
public boolean equals(Object o) {
        if (!(o instanceof Deque)) {
            return false;
        }
        ArrayDeque otherarr = (ArrayDeque) o;

        if (otherarr.size != this.size) {
            return false;
        }

        for (int i = 0; i < array.length; i  ) {
            type part1 = this.array[(head   1   i) % array.length];
            type part2 = (type) otherarr.get(i);
            if (part1 != part2) {
                return false;

Sample Expectation

        ArrayDeque<Integer> x = new ArrayDeque<Integer>();
        ArrayDeque<Integer> y = new ArrayDeque<Integer>();
        for (int i = 0; i < 100000000; i  ) {
            x.addLast(i);
            y.addLast(i);
        }
        System.out.println(x.equals(y));

Expected: True
Actual: False

CodePudding user response:

== compares the memory of the values while .equals() compares the values themselves.

Replace:

for (int i = 0; i < array.length; i  ) {
    type part1 = this.array[(head   1   i) % array.length];
    type part2 = (type) otherarr.get(i);
    if (part1 != part2) {
        return false;
    }
}

with:

for (int i = 0; i < this.size(); i  ) {
    type part1 = this.array[(head   1   i) % array.length];
    type part2 = (type) otherarr.get(i);
    if (!(part1.equals(part2))) {
        return false;
    }
}

CodePudding user response:

== compares reference identity - java's types always store a reference. Given String x = "foo", think x is a page in an address book; "foo" is a house. The x page has the address of that house on it.

== checks if the addresses are the same. If you happen to have 2 identically built houses on different addresses, x == y checks addresses and would conclude false - not the same. x.equals(y) walks over to the house you find at the address on the x page, and asks that house: Hey, here is a copy of my y page, can you go tell me if you are identical to it?

And that's what you want here.

You might think: Wait, I have integers, those are primitives, they aren't references.

Not quite. Generics can't (currently - we're all waiting for Project Valhalla to change this) store primitives at all, so everything is modified automatically into Integer, which is a reference type.

Java initializes this class with all byte values (So, -128 to 127) as a 'cache' of sorts, hence you get this bizarro result:

Integer a = Integer.valueOf(20);
Integer b = Integer.valueOf(20);
System.out.println(a == b); // true
a = Integer.valueOf(127);
b = Integer.valueOf(127);
System.out.println(a == b); // true
a = Integer.valueOf(128);
b = Integer.valueOf(128);
System.out.println(a == b); // false!

and 128 happens to be your very last number.

The solution? Don't compare with ==, compare with a.equals(b). If you want to consider null to be equal to null (a somewhat dubious proposition; for example, in the SQL take on what null means, that is not true: That'd be the take where null means unset or unknown, and it is not possible to determine if 2 unknown values are equal to each other). However, if you really want that, Objects.equals(a, b), or simply a == null ? b == null : a.equals(b) is what you'd want instead.

  • Related