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