3

In another question, my code has such a equals method:

public class Length {

    private final double value;
    private final Unit unit;

    public Length(double value, Unit unit) {
        this.value = value;
        this.unit = unit;
    }

    @Override
    public boolean equals(Object obj) {
        Length length = (Length) obj;
        return this.unit.toMM(this.value) == length.unit.toMM(length.value);
    }
}

I want to compare two Lengths, they are equal to each other if they can be converted to the same unit with same length value

@weston gives me some very good explanations under this answer about why I should not use equals here, but I still not quite clear.

Community
  • 1
  • 1
Freewind
  • 193,756
  • 157
  • 432
  • 708
  • This is unclear. I didn't read in the linked answer that you should not override `equals`. – Tunaki Dec 02 '15 at 15:16
  • It seems mostly a matter of opinion. It's *uncommon* to refer to other types/values in `equals()`, but if that's how your object defines equality then that's how it defines equality. It's probably more straightforward to just check if `value` itself is equal and `unit` is "equal" (however that type defines equality). – David Dec 02 '15 at 15:18
  • See the 2nd paragraph, `It's equals, not equivalent, if you want to have that behaviour, give it another name (suggestion isSameLength)` – Freewind Dec 02 '15 at 15:18
  • 1
    The point, which, I'm not sure if I agree with or not, is that equals should compare two objects as they exist in memory, not after you have applied some operation on it. 1cm is the same as 10mm, but they would be represented differently. This is a semantic issue, not a technical one. – bstockwell Dec 02 '15 at 15:20
  • You get to decide whether or not this is appropriate. It's a perfectly valid definition. – Louis Wasserman Dec 02 '15 at 18:30

1 Answers1

3

Essentially, he is saying that 10mm and 1cm should not be equal. That is debatable and up to you to decide.

As a reference, you could take an approach similar to BigDecimal's:

new BigDecimal("1.0").equals(new BigDecimal("1.00"))    //false
new BigDecimal("1.0").compareTo(new BigDecimal("1.00")) //0

Another example is java.time.Period:

Note that this means that a period of "15 Months" is not equal to a period of "1 Year and 3 Months".

Or you may as well decide that 10 mm and 1 cm are equal. Take for example java.time.Duration:

The comparison is based on the total length of the durations.

In the end, what is important is to clearly document what is being done.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • Thanks for these great examples! And I think maybe I should follow @ weston's advise, since if I defined `equals`, I should define `hashcode`, but if I define it correctly, I should do `this.unit.toMM(this.value)` again in `hashcode` to make it right. That looks strange then. I found `java.time.Duration` contains all the values it needs and doesn't need to do extra converting in `hashcode` – Freewind Dec 02 '15 at 15:35