java - Library function to do bean comparison using Functions? -
since java 8 has made easier ever refer method directly (function/lambda), traditional reflection-based bean comparators (e.g. common-lang's equalsbuilder) can implemented cleanly without reflection. wondering available in well-known library already?
just clear, after function similar signature:
static <t> boolean equals(t a, t b, function<t, ?>... proprefs);   alternatively, non-confusion way of implementing using streams?
given example class like
class person {     long id;     string name, surname;     int age;      public long getid() {         return id;     }     public string getname() {         return name;     }     public string getsurname() {         return surname;     }     public int getage() {         return age;     } }   of course, can in compact form like
@override public boolean equals(object obj) {     if(obj==this) return true;     if(!(obj instanceof person)) return false;     person p=(person)obj;     return stream.<function<person,?>>of(           person::getname, person::getsurname, person::getage)       .allmatch(f->objects.equals(f.apply(this), f.apply(p))); }   but raises big question whether win compared simple form
@override public boolean equals(object obj) {     if(obj==this) return true;     if(!(obj instanceof person)) return false;     person p=(person)obj;     return this.age==p.age && objects.equals(this.name, p.name)       && objects.equals(this.surname, p.surname); }   as doesn’t add brevity of code , can’t prevent neither, forgetting significant property nor mismatches between equals implementation , hashcode implementation.
note applies equalsbuilder; it’s not helping regarding critical issues (actually, can’t see any advantage).
if want gain advantage out of it, have resort not-so compact implementation:
static list<function<person,?>> eq_props=arrays.aslist(     person::getname, person::getsurname, person::getage);  @override public boolean equals(object obj) {     if(obj==this) return true;     if(!(obj instanceof person)) return false;     person p=(person)obj;     return eq_props.stream().allmatch(f->objects.equals(f.apply(this), f.apply(p))); } @override public int hashcode() {     return objects.hash(eq_props.stream().map(f->f.apply(this)).toarray()); }   we still can’t guaranty there no relevant property missing, @ least have single point of responsibility need check , have ensured equality , hash code consistent, there one advantage on manual implementation.
if worry performance implication of temporary objects, may combine functions actual operation can performed without temporary object:
static list<function<person,?>> eq_props=arrays.aslist(     person::getname, person::getsurname, person::getage);  static bipredicate<person,person> equal=eq_props.stream()     .<bipredicate<person,person>>map(f -> (a,b) -> objects.equals(f.apply(a), f.apply(b)))     .reduce(bipredicate::and).get();  static tointfunction<person> hash=eq_props.stream()     .<tointfunction<person>>map(f -> -> objects.hash(f.apply(a)))     .reduce((f,g) -> x -> f.applyasint(x)*31+g.applyasint(x)).get();  @override public boolean equals(object obj) {     return obj==this || (obj instanceof person)&& equal.test(this, (person)obj); } @override public int hashcode() {     return hash.applyasint(this); }      
Comments
Post a Comment