[
https://issues.apache.org/jira/browse/LANG-1493?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Miguel Munoz updated LANG-1493:
-------------------------------
Description:
The EqualsBuilder.reflectionEquals() method is very inefficient. It reflects
through all the fields of a class every time it needs to do a comparison. A
faster approach would be to do the reflection once when the class loads, and
re-use it for each instance. This change, however, needs a different API and
couldn't be a drop-in replacement for EqualsBuilder. Instead it would need to
be a new class.
I have written a class that can do this. Performance tests show that, when
using reflection, it runs up to 20 times faster than reflectionEquals(),
depending on how many fields it needs to compare before finding a difference.
You can try the class out by going to [https://github.com/SwingGuy1024/DogTags].
The API currently works like this:
{code:java}
public class MyClass {
// fields and methods omitted for brevity
// Use reflection to implement equals() and hashCode() based on all non
transient, non static fields
private static final DogTag.Factory<MyClass> factory =
DogTag.create(MyClass.class).build();
private final DogTag<MyClass> dogTag = factory.tag(this);
@Override
public boolean equals(Object that) {
return dogTag.equals(that);
}
@Override
public int hashCode() {
return dogTag.hashCode();
}
}{code}
An alternative way to do this is to specify function pointers. This fills the
same niche as creating an EqualsBuilder.
{code:java}
public class MyClass2 {
private String name;
private int age;
public MyClass2(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name;}
public int getAge() { return age;}
private static final DogTag.Factory<MyClass2> factory =
DogTag.createByLambda(MyClass2.class)
.addSimple(MyClass2::getAge)
.addObject(MyClass2::getName)
.build();
private final DogTag<MyClass2> dogTag = factory.tag(this);
@Override
public int hashCode() {
return dogTag.hashCode();
}
@Override
public boolean equals(final Object obj) {
return dogTag.equals(obj);
}
}
{code}
Either way, these have the advantage of ensuring that equals() and hashCode()
are consistent.
(I'm a new contributor, so I'm not sure if this is the best way to suggest a
whole new class. But I'd like to contribute to give people a faster way of
doing Reflection Equals.)
was:
The EqualsBuilder.reflectionEquals() method is very inefficient. It reflects
through all the fields of a class every time it needs to do a comparison. A
faster approach would be to do the reflection once when the class loads, and
re-use it for each instance. This change, however, needs a different API and
couldn't be a drop-in replacement for EqualsBuilder. Instead it would need to
be a new class.
I have written a class that can do this. Performance tests show that it runs
up to 20 times faster, depending on how many fields it needs to compare before
finding a difference.
You can try the class out by going to [https://github.com/SwingGuy1024/DogTags].
The API currently works like this:
{code:java}
public class MyClass {
// fields and methods omitted for brevity
// Use reflection to implement equals() and hashCode() based on all non
transient, non static fields
private static final DogTag.Factory<MyClass> factory =
DogTag.create(MyClass.class).build();
private final DogTag<MyClass> dogTag = factory.tag(this);
@Override
public boolean equals(Object that) {
return dogTag.equals(that);
}
@Override
public int hashCode() {
return dogTag.hashCode();
}
}{code}
An alternative way to do this is to specify function pointers
{code:java}
public class MyClass2 {
private String name;
private int age;
public MyClass2(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name;}
public int getAge() { return age;}
private static final DogTag.Factory<MyClass2> factory =
DogTag.createByLambda(MyClass2.class)
.addSimple(MyClass2::getAge)
.addObject(MyClass2::getName)
.build();
private final DogTag<MyClass2> dogTag = factory.tag(this);
@Override
public int hashCode() {
return dogTag.hashCode();
}
@Override
public boolean equals(final Object obj) {
return dogTag.equals(obj);
}
}
{code}
(I'm a new contributor, so I'm not sure if this is the best way to suggest a
whole new class. But I'd like to contribute to give people a faster way of
doing Reflection Equals.)
> Performance of Reflection for equals and hash code can be improved over
> EqualsBuilder
> -------------------------------------------------------------------------------------
>
> Key: LANG-1493
> URL: https://issues.apache.org/jira/browse/LANG-1493
> Project: Commons Lang
> Issue Type: New Feature
> Components: lang.*
> Reporter: Miguel Munoz
> Priority: Major
> Original Estimate: 672h
> Remaining Estimate: 672h
>
> The EqualsBuilder.reflectionEquals() method is very inefficient. It reflects
> through all the fields of a class every time it needs to do a comparison. A
> faster approach would be to do the reflection once when the class loads, and
> re-use it for each instance. This change, however, needs a different API and
> couldn't be a drop-in replacement for EqualsBuilder. Instead it would need to
> be a new class.
> I have written a class that can do this. Performance tests show that, when
> using reflection, it runs up to 20 times faster than reflectionEquals(),
> depending on how many fields it needs to compare before finding a difference.
> You can try the class out by going to
> [https://github.com/SwingGuy1024/DogTags].
> The API currently works like this:
>
> {code:java}
> public class MyClass {
> // fields and methods omitted for brevity
>
> // Use reflection to implement equals() and hashCode() based on all non
> transient, non static fields
> private static final DogTag.Factory<MyClass> factory =
> DogTag.create(MyClass.class).build();
> private final DogTag<MyClass> dogTag = factory.tag(this);
>
> @Override
> public boolean equals(Object that) {
> return dogTag.equals(that);
> }
>
> @Override
> public int hashCode() {
> return dogTag.hashCode();
> }
> }{code}
> An alternative way to do this is to specify function pointers. This fills the
> same niche as creating an EqualsBuilder.
> {code:java}
> public class MyClass2 {
> private String name;
> private int age;
>
> public MyClass2(String name, int age) {
> this.name = name;
> this.age = age;
> }
> public String getName() { return name;}
> public int getAge() { return age;}
>
> private static final DogTag.Factory<MyClass2> factory =
> DogTag.createByLambda(MyClass2.class)
> .addSimple(MyClass2::getAge)
> .addObject(MyClass2::getName)
> .build();
> private final DogTag<MyClass2> dogTag = factory.tag(this);
> @Override
> public int hashCode() {
> return dogTag.hashCode();
> }
> @Override
> public boolean equals(final Object obj) {
> return dogTag.equals(obj);
> }
> }
> {code}
> Either way, these have the advantage of ensuring that equals() and hashCode()
> are consistent.
> (I'm a new contributor, so I'm not sure if this is the best way to suggest a
> whole new class. But I'd like to contribute to give people a faster way of
> doing Reflection Equals.)
--
This message was sent by Atlassian Jira
(v8.3.4#803005)