Just tried to test speed of equals when using Objects.equals vs Primitive comparison. If somebody needs the code:
import org.junit.Test;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
class BaseEquals {
byte bytePrim;
short shortPrim;
int intPrim;
long longPrim;
float floatPrim;
double doublePrim;
boolean booleanPrim;
char charPrim;
BaseEquals() {
bytePrim = 1;
shortPrim = 1;
intPrim = 1;
longPrim = 1;
floatPrim = 1.0f;
doublePrim = 1.0d;
booleanPrim = true;
charPrim = '1';
}
}
class EqualsObjects extends BaseEquals {
@Override
public int hashCode() {
return Objects.hash(bytePrim,
shortPrim,
intPrim,
longPrim,
floatPrim,
doublePrim,
booleanPrim,
charPrim);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof EqualsObjects)) {
return false;
}
EqualsObjects eo = (EqualsObjects)obj;
return Objects.equals(bytePrim, eo.bytePrim)
&& Objects.equals(shortPrim, eo.shortPrim)
&& Objects.equals(intPrim, eo.intPrim)
&& Objects.equals(longPrim, eo.longPrim)
&& Objects.equals(floatPrim, eo.floatPrim)
&& Objects.equals(doublePrim, eo.doublePrim)
&& Objects.equals(booleanPrim, eo.booleanPrim)
&& Objects.equals(charPrim, eo.charPrim);
}
}
class EqualsPrimitives extends BaseEquals {
@Override
public int hashCode() {
return Objects.hash(bytePrim,
shortPrim,
intPrim,
longPrim,
floatPrim,
doublePrim,
booleanPrim,
charPrim);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof EqualsPrimitives)) {
return false;
}
EqualsPrimitives eo = (EqualsPrimitives)obj;
return bytePrim == eo.bytePrim
&& shortPrim == eo.shortPrim
&& intPrim == eo.intPrim
&& longPrim == eo.longPrim
&& Float.compare(floatPrim, eo.floatPrim) == 0
&& Double.compare(doublePrim, eo.doublePrim) == 0
&& booleanPrim == eo.booleanPrim
&& charPrim == eo.charPrim;
}
}
public class EqualsTests {
@State(Scope.Benchmark)
public static class MyState {
EqualsObjects eo1;
EqualsObjects eo2;
EqualsPrimitives ep1;
EqualsPrimitives ep2;
@Setup
public void setup() throws Throwable {
eo1 = new EqualsObjects();
eo2 = new EqualsObjects();
ep1 = new EqualsPrimitives();
ep2 = new EqualsPrimitives();
}
}
@Benchmark
public void equalsObject(MyState state) throws Throwable {
boolean b1 = state.eo1.equals(state.eo2);
boolean b2 = state.eo2.equals(state.eo1);
}
@Benchmark
public void equalsPrimitive(MyState state) throws Throwable {
boolean b1 = state.ep1.equals(state.ep2);
boolean b2 = state.ep2.equals(state.ep1);
}
@Test
public void launch() throws RunnerException {
Options options = new OptionsBuilder()
.include(this.getClass().getName() + ".*")
.mode(Mode.AverageTime)
.timeUnit(TimeUnit.MICROSECONDS)
.warmupTime(TimeValue.seconds(1))
.warmupIterations(5)
.measurementTime(TimeValue.seconds(5))
.measurementIterations(10)
.threads(2)
.forks(1)
.shouldFailOnError(true)
.shouldDoGC(true)
.build();
new Runner(options).run();
}
}
What I saw in the end is this results:
Benchmark Mode Cnt Score Error Units
EqualsTests.equalsObject avgt 10 0.026 ± 0.001 us/op
EqualsTests.equalsPrimitive avgt 10 0.011 ± 0.001 us/op
Do you think it is worth using primitive comparison to have faster equals methods (probably neglectable to other operations in code), or using Objects.equals to have unified code (not to think about using Double.compare and Float.compare for double and float primitives respectively, and == for other primitives) in equals method?