Here's the code of ObjectUtils.equals(..):
public static boolean equals(Object object1, Object object2) {
if (object1 == object2) {
return true;
}
if ((object1 == null) || (object2 == null)) {
return false;
}
return object1.equals(object2);
}
ObjecUtils docs state clearly that objects passed can be null.
Now on the matter whether true should be returned if you compare two nulls. In my opinion - no, because:
- when you compare two objects, you are probably going to do something with them later on. This will lead to a
NullPointerException - passing two
nulls to compare means that they got from somewhere instead of "real" objects, perhaps due to some problem. In that case comparing them alone is wrong - the program flow should have halted before that. - In a custom library we're using here we have a method called
equalOrBothNull()- which differs from theequalsmethod in this utility in the null comparison.
Here's the code of ObjectUtils.equals(..):
public static boolean equals(Object object1, Object object2) {
if (object1 == object2) {
return true;
}
if ((object1 == null) || (object2 == null)) {
return false;
}
return object1.equals(object2);
}
ObjecUtils docs state clearly that objects passed can be null.
Now on the matter whether true should be returned if you compare two nulls. In my opinion - no, because:
- when you compare two objects, you are probably going to do something with them later on. This will lead to a
NullPointerException - passing two
nulls to compare means that they got from somewhere instead of "real" objects, perhaps due to some problem. In that case comparing them alone is wrong - the program flow should have halted before that. - In a custom library we're using here we have a method called
equalOrBothNull()- which differs from theequalsmethod in this utility in the null comparison.
Am I right to be concerned and to want to avoid using the ObjectUtils.equals() where ever possible?
No. What you need to consider equals depends on your requirements. And wanting to consider two nulls equal and any non-null unequal to a null without having to deal with NullPointerExceptions is a very, very common requirement (e.g. when you want to fire value-change events from a setter).
Actually, it's how equals() in general should work, and typically, half of that behvaiour is implemented (the API doc of Object.equals() states "For any non-null reference value x, x.equals(null) should return false.") - that it doesn't work the other way round is mainly due to technical restrictions (the language was designed without multiple dispatch to be simpler).
You can simply use Apache Commons Lang:
result = ObjectUtils.compare(firstComparable, secondComparable)
Using Java 8:
private static Comparator<String> nullSafeStringComparator = Comparator
.nullsFirst(String::compareToIgnoreCase);
private static Comparator<Metadata> metadataComparator = Comparator
.comparing(Metadata::getName, nullSafeStringComparator)
.thenComparing(Metadata::getValue, nullSafeStringComparator);
public int compareTo(Metadata that) {
return metadataComparator.compare(this, that);
}
Your Question is very vague, I don't really know what you are talking about, so I'll go in several Directions.
"compare my Objects" can mean several things. In Java, this usually means comparing them for sorting, i.e. through the Comparable / Comparator interfaces. While ObjectUtils does provide a null-safe compare method, it won't help you beyond that. What you need is either a custom Comparator or for your objects to implement Comparable. CompareToBuilder can help you with both, to a certain extent:
public class SomeBean implements Comparable<SomeBean>{
private String foo;
private int bar;
private List<String> baz;
public int compareTo(SomeBean other) {
return new CompareToBuilder()
.append(foo, other.foo)
.append(bar, other.bar)
.append(baz, other.baz)
.toComparison();
}
}
If, on the other hand, you want to compare the properties of different object types, then you are looking in the totally wrong direction. Have a look at Commons / BeanUtils instead. Sample code:
public class BeanUtilsTester {
public static class Foo{
private String foo="foo";
public String getFoo() {return foo;}
public void setFoo(String foo) {this.foo = foo;}
private Integer bar=123;
public Integer getBar() {return bar;}
public void setBar(Integer bar) {this.bar = bar;}
private List<String> squoggle=Arrays.asList("abc","def");
public List<String> getSquoggle() {return squoggle;}
public void setSquoggle(List<String> squoggle) {this.squoggle = squoggle;}
}
public static class Bar{
private String foo="bar";
public String getFoo() {return foo;}
public void setFoo(String foo) {this.foo = foo;}
private Integer bar=456;
public Integer getBar() {return bar;}
public void setBar(Integer bar) {this.bar = bar;}
private String[] fiddle=new String[]{"abc","def"};
public String[] getFiddle() {return fiddle;}
public void setFiddle(String[] fiddle) {this.fiddle = fiddle;}
}
public static void main(String[] args) throws Exception{
Foo foo = new Foo();
Bar bar = new Bar();
Map<String,Object> fooProps = BeanUtils.describe(foo);
Map<String,Object> barProps = BeanUtils.describe(bar);
fooProps.keySet().retainAll(barProps.keySet());
BeanUtils.populate(bar, fooProps);
assertEquals(foo.getFoo(),bar.getFoo());
assertEquals(foo.getBar(), bar.getBar());
}
}
And if you just want to implement equals() correctly, look at EqualsBuilder:
@Override
public boolean equals(Object obj) {
if (obj instanceof SomeBean) {
SomeBean other = (SomeBean) obj;
return new EqualsBuilder()
.append(foo, other.foo)
.append(bar, other.bar)
.append(baz, other.baz)
.isEquals();
}
return false;
}
ObjectUtils will work just fine with comparing user defined objects. Of course you'll need to implement the Comparable interface in any object that you'd like to compare using the library functions.