So here's something that has me really mystified about Java.
Let's say you want a simple class to represent a simple value object. Just a garden-variety thingamabob that has -- let's just say two fields. And these two fields together give the object its identity.
And you want this class of yours to be simple, basic, idiomatic and well-behaved.
This seems like a pretty common thing to want to do, right? So far so good?
Better flex those fingers!
public class Foo implements Serializable, Cloneable {
private String text;
private Integer number;
public Foo(String text, Integer number) {
this.text = text;
this.number = number;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
@Override public boolean equals(Object object) {
if (object instanceof Foo) {
Foo that = (Foo) object;
// oops! I cheated and used a Google-internal helper class!
return Objects.equal(this.text, that.text)
&& Objects.equal(this.number, that.number);
}
return false;
}
@Override public int hashCode() {
// oops! I did it again! ha ha!
return Objects.hashCode(text, number);
}
@Override public String toString() {
return String.format("(%s, %s)", text, number);
}
@Override public Foo clone() {
try {
return (Foo) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(e); // impossible
}
}
private static final long serialVersionUID = 0xB0B15C00L;
}
Now, in my native language we have an expression for this situation, which loosely translates as, "what the mother****ing ****???"
What the hell happened? What did we do to deserve this? We just typed forty-four lines of code, not counting any documentation, just to create a ****ing struct, for Christ's sake! And we even had helper methods to call on for everything we reasonably could, at that!
And we'll end up typing it again. And again, and again. Except that in each place in our whole system we discover this pattern, it will have been deviated from in some subtle way or another. Forgot to make it cloneable, Forgot to make it serializable, a typo in equals() -- and tell the truth now, have you never once made that most appalling error of forgetting to implement hashCode()? Really?
So, we'd better write unit tests for all these classes too, then.
Object-oriented languages are meant to save us from duplication. But what we have here is a bona fide disaster. Something has failed us. But what can we reasonably do about it?
This I will address.... in the next post!