Java compare the elements of a class - java

I have a class name "Users" and have 2 elements (int)userId and (String)userName.
Let's said
Users obj1 = new Users(10, "User1");
Users obj2 = new Users(11, "User2");
So I want to compare obj1 to obj2
element by element
10 compare to 11,
"User1" compare to "User2".
From the research i do from web. It looks like impossible to do it whether convert it to 2d array to compare or whatever method. Is there any method to do this kind of things?
I actually want to do an audit trail so i have the object before changes and after changes, so whatever element that have changed will insert a new record in the audit_trail table with the before value and after value.
I'm a newbie to programming i tried my best to think a way but it just doesn't work. Is there any other way of doing this by SQL? i using ng-admin as (front-end) and API java http to do a update (back-end).

You need to implement the Comparable<Users> interface. If you want equality check too, then you have to override
boolean equals(Object)
and
int hashCode()
Read:
https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html
and
Why do I need to override the equals and hashCode methods in Java?

From your question, We can compare two different objects.
Please implement the equals method to do your operations available in Comparable<Users>.
Let's say as a example below,
Class obj1 = new Class(1, "raja");
Class obj2 = new Class(2, "thiru");
The id and name are a public variable of the class. Then
override the function as,
public boolean equals(Object obj)
{
return (this.id == obj.id && this.name.equals(obj.name.equals));
}
Thanks.

You should override the .equals() method, making your Users class as follows:
public class Users {
private int mId;
private String mName;
public Users(int pId, String pName) {
mId = pId;
mName = pName;
}
public int getId() {
return mId;
}
#Override
public boolean equals(Object pObject) {
return (pObject instanceof Users && ((Users) pObject).getId() == mId);
}
}

I'd probably create a BeanDelta object
public class PropertyDelta {
private String propertyName;
private Object value1;
private Object value2;
// constructor & getters
}
public class BeanDelta<T> {
private Class<T> type;
private List<PropertyDelta> propertyDeltas = new ArrayList<>();
public BeanDelta(Class<T> type) {
this.type = type;
}
// getters
}
Then you could write a reflection based method
public <T> BeanDelta<T> getDelta(T o1, T, o2) {
Class<T> type = o1.getClass();
Method[] methods = type.getMethods();
BeanDelta<T> delta = new BeanDelta<>(type);
for (Method meth : methods) {
boolean isGetter = method.getParameterTypes().length == 0 && !method.getReturnType().equals(void.class) && meth.getName().startsWith("get");
if (isGetter) {
Object v1 = meth.invoke(o1);
Object v2 = meth.invoke(o2);
if (!Objects.equal(v1, v2)) {
String propertyName = meth.getName().substring(3);
delta.propertyDeltas.add(new PropertyDelta(propertyName, v1, v2));
}
}
}
return delta;
}

Check it out the solution proposed for do that.
http://www.codejava.net/java-core/collections/sorting-a-list-by-multiple-attributes-example

Related

COMPARABLE - How to see if elements from objects are equals?

Im devoloping a program that i put some elements into my object within an ArrayList... this is my code
import java.util.ArrayList;
public class ListaConcepto {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<CompararListas> Lista = new ArrayList<CompararListas>();
CompararListas obj1 = new CompararListas("abc", 12.25, "lala", 2);
CompararListas obj2 = new CompararListas("abc", 13.50, "lala", 3);
CompararListas obj3 = new CompararListas("poc", 12.50, "jaja", 1);
Lista.add(obj1);
Lista.add(obj2);
Lista.add(obj3);
}
}
Then... this is my class with the interface Comparable... and i need a method to implement to see if elements are EQUALS then print the result.
public class CompararListas implements Comparable<CompararListas> {
private String referencia;
private double monto;
private String descripcion;
private double NumeroParte;
public CompararListas(String referencia, double monto, String descripcion, double numeroParte) {
this.referencia = referencia;
this.monto = monto;
this.descripcion = descripcion;
this.NumeroParte = numeroParte;
}
public double getMonto() {
return monto;
}
public void setMonto(double monto) {
this.monto = monto;
}
public String getDescripcion() {
return descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
public double getNumeroParte() {
return NumeroParte;
}
public void setNumeroParte(double numeroParte) {
NumeroParte = numeroParte;
}
public String getReferencia() {
return referencia;
}
public void setReferencia(String referencia) {
this.referencia = referencia;
}
#Override
public int compareTo(CompararListas o) {
// TODO Auto-generated method stub
return 0;
}
}
Remember Comparable is meant to be used to decide the relationship between to items for the purposes of ordering; it's not quite for equality. In fact, there's no requirement that any two comparable items must be equal.
In your case, you may want to order by NumeroParte, which means "Part Number" and seems like a sensible choice. Every type of data has a different way to be organized.
Your method may look something like
public int compareTo(ComprarListas o){
return this.NumeroParte - o.getNumeroParte();
}
Which works because both are integer numbers.
Or the appropriate property of your object - you may want to order based on price instead for instance.
If you want to know just if an object is equal to another you have to implemet the equals method (which doesn't requiere you to declare any interface, every class can do it)
#Override
public boolean equals(Object o) {
CompararListas other = (CompararListas) o;
return ...
}
with this method you can return what makes the two objects equals to you, if you just have to look for referencia.equals(other.referencia) or if you have to compare every property like referencia.equals(other.referencia) && monto == other.monto && ...
But if you want to compare elements in order to do something like ordering them there you have to implement the Comparable interface and implement the compareTo method
#Override
public int compareTo(CompararListas o) {
if (NumeroParte < o.NumeroParte)
return -1;
else if (NumeroParte > o.NumeroParte)
return 1;
return 0;
}
This will make the objects able to compare each other and for example know if one is "smaller" than other according to your criteria (in this example I only used NumeroParte and made it explicit to be easy to understand, but the key is that you can use any criteria you want to compare the objects and if you want order them later).
These are solutions to different problems, you have to identify which one is the better in your case.

Get command of a hashmap with a parameter different than the key in the hashmap?

I have a custom class as my key in my hashmap like so
// In the main function
HashMap<Drink, boolean> drinkMap = new HashMap<>();
// What I would like to be able to do:
drinkMap.get("beer");
// My drink Class which is used as the key
public class Drink implements Comparable<String> {
private String name;
private String info;
public String getName() {
return Name;
}
public Drink(String name, String info) {
this.name = name;
this.info = info;
}
}
What I want to do is have the get method for the hashmap compare the string that is passed in to Drink.name and if they are the same then return that hashmap entry, but I cannot figure out how to get this to work.
I tried implementing the equals and hashcode methods in my Drink class like so:
#Override
public int hashCode() {
return Name.hashCode();
}
#Override
public boolean equals(Object o) {
return o instanceof String && o.equals(Name);
}
But when I would do hashMap.get("beer") it kept returning null even though I know there exists a Drink object with the name "beer" in the map.
This is a terrible idea. You should always query a map with the same type (or a subtype thereof) as the intended key. Not doing that only opens you up to problems (as I'm sure you've started to notice).
You should consider either making the key of your map a String type, or querying your map by Drink.
(As to why your specific case isn't working: "beer".equals(drink) != drink.equals("beer").)

achieving polymorphism within the parent class by using instanceof to set attribute

I have a parent class called AggDef which is the base type of some child classes (TermAggDef, StatAggDeff etc.). The class is defined below.
I have some code in another class that loops over a list of AggDef objects and get's their types.
protected Map aggregations = new HashMap();
public List<String> getAggregationTypes(){
HashSet<String> aggTypes = new HashSet<String>();
Iterator it = aggregations.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
AggDef aggDef = (AggDef) pair.getValue();
aggTypes.add(aggDef.getType());
}
List<String> retList = new ArrayList<String>();
retList.addAll(aggTypes);
return retList;
}
My Question is, could I achieve this polymorphic assignment of the type attribute in the parent class itself? Because wherever an AggDef object would be used, it would know what specific type it is. My team member said I should implement the setType method in the actual child classes. But I don't think what I have here is wrong. Any help or elaboration on the accuracy of my approach would be very helpful. Thank you in advance.
public abstract class AggDef implements Cloneable {
protected String name;
protected String term;
protected String type;
...
protected List<AggDef> subAggregations;
public void setType(AggDef def){
if(def instanceof TermAggDef){
def.type = "terms";
}
else if (def instanceof StatAggDef){
def.type = "terms_stats";
}
else if (def instanceof RangeAggDef){
def.type = "range";
}
}
public String getType(){
return type;
}
protected AggDef() {
setType(this);
}
protected AggDef(String term) {
this.term = term;
setType(this);
}
protected AggDef(String name, String term) {
this.name = name;
this.term = term;
setType(this);
}
public AggDef(String term, String order, int size, int offset, boolean isAllTerms) {
this.term = term;
this.size = size;
...
setType(this);
}
public AggDef(String name, String term, String order, int size, int offset, boolean isAllTerms) {
this.name = name;
this.term = term;
...
setType(this);
}
}
AggDef only knows about itself and can never know anything about it's children. So when it calls setType(AggDef) the JVM will reference the locally defined method and not the over-riden.
Hopefully, to help further nail the subject in let's say you have:
AggDef aDefObj = new AggDef();
TermAggDef taDefObj = new TermAggDef();
then that means the following:
aDefObj instanceOf AggDef // true
aDefObj instanceOf TermAggDef // false
taDefObj instanceOf AggDef // true
taDefObj instanceOf TermAggDef // true
Check out Oracle's Inheritance doc specifically Casting.

Access to array list many times

I have list (array list)that can contain many instances (between 500-3000 instances ).
during the program some function need to access to this list (many times)and search for specific instance or more ,to get the instance\s they need loop on the list and provide parentName and name (which is string) and are not uniqe key .
my question is since the list need to be accessed many time there is a way to define/design it better that the access to the list can be more efficient?
Please keep in mind that the functions that need to get instance/s from the list
cannot provide full key the can provide only name and parentName which can have more that one instance.
List<Obj> myList = new ArrayList<Obj>();
class obj
{
parentName
Name
type
curr
....
Use a Map<MyEntry, List<Obj>> where MyEntry is a class enclosing parent name and name as such:
public final class MyEntry
{
private final String parentName;
private final String name;
private final int hashCode;
public MyEntry(final String parentName, final String name)
{
this.parentName = parentName;
this.name = name;
hashCode = 31 * parentName.hashCode() + name.hashCode();
}
// Override .equals() and .hashCode()
#Override
public int hashCode()
{
return hashCode;
}
#Override
public boolean equals(final Object o)
{
if (this == o)
return true;
if (o == null)
return false;
if (getClass() != o.getClass())
return false;
final MyEntry other = (MyEntry) o;
return parentName.equals(other.parentName)
&& name.equals(other.name);
}
// Have a nice string representation
#Override
public String toString()
{
return "parent name: " + parentName + ", name: " + name;
}
}
You can, for instance, have a method in your Obj which returns the matching MyEntry object. Also, if you use Guava, have a look at MultiMap.
You will notice that the hash code is precomputed: this can be done since the MyEntry class is immutable. This allows for very fast usage as keys for a Map.
(edit: added .toString())

Remove duplicate objects from a ArrayList in Android

I know this has be discussed over and over again here, but none of the examples I've tried worked for me.
What I've got
I access the Call log from Android and I get a list of all calls made. Of course, here I get a lot of duplicates.
First I make a List
List<ContactObject> lstContacts = new ArrayList<ContactObject>();
Then I add objects into it
While (get some record in call log)
{
ContactObject contact = new ContactObject();
contact.SetAllProperties(......)
lstContacts.add(contact);
}
Set<ContactObject> unique = new LinkedHashSet<ContactObject>(lstContacts);
lstContacts = new ArrayList<ContactObject>(unique);
The Contact Object class is simple
public class ContactObject {
public ContactObject() {
super();
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof ContactObject))
return false;
return this.lstPhones == ((ContactObject) obj).getLstPhones();
}
#Override
public int hashCode() {
return lstPhones.hashCode();
}
private long Id;
private String name;
private List<String> lstPhones;
private String details;
//... getters and settres
}
What I need
I need to have a Contact only once in the list. As I've read around here there are a couple of things that can be done like Set, HashSet, TreeSet. TreeSet seems the best as it keeps the order just as I receive it from the Call log. I've tried to make my code work with it but no success. Could anyone be so kind to give me a sample code based on my example. Thank you for your time.
The Working Solution. Thank you all for your support, you've made my day.
In ContactObject override the two methods
#Override
public boolean equals(Object obj) {
if (!(obj instanceof ContactObject))
return false;
return lstPhones.equals(((ContactObject) obj).getLstPhones());
}
#Override
public int hashCode() {
return (lstPhones == null) ? 0 : lstPhones.hashCode();
}
//Getters and Setters and COnstructor....
Simply use it as
Set<ContactObject> unique = new LinkedHashSet<ContactObject>(lstContacts);
lstContacts = new ArrayList<ContactObject>(unique);
LinkedHashSet which keeps insertion-order can be used in your case.
HashSet: no order.
TreeSet: sorted set, but not keep insertion order.
EDIT: As Software Monkey commented, hashCode() and equals() should be overwritten in ContactObject to fit the hash-based Set.
Remove duplication of Custom Object
Example of Removing duplicate using Comparator
Lets suppose you have a class "Contact"
public class Contact implements Comparable<Contact> {
public String getName() {
return this.Name;
}
public void setName(String name) {
this.Name = name;
}
public String getNumber() {
return this.Number;
}
public void setNumber(String number) {
this.Number = number;
}
///// this method is very important you must have to implement it.
#Override
public String toString() {
return "\n" +"Name=" + name + " Number=" + Number;
}
Here is how you can remove duplicate entries using Set , just pass your list in the function and it will work for you. New list will be returned which will have no duplicated contacts.
public ArrayList<Contact> removeDuplicates(ArrayList<Contact> list){
Set<Contact> set = new TreeSet(new Comparator<Contact>() {
#Override
public int compare(Contact o1, Contact o2) {
if(o1.getNumber().equalsIgnoreCase(o2.getNumber())){
return 0;
}
return 1;
}
});
set.addAll(list);
final ArrayList newList = new ArrayList(set);
return newList;
}
It worked for me so please try and give me your feedback. Thanks
P.S: Credit goes to Nilanchala at this article
For sure you can use TreeSet to store only once but a common mistake is do not override hashCode() and equal() methods:
This can fit for you:
public boolean equals(Object obj) {
if (!(obj instanceof ContactObject))
return false;
return this.id == ((ContactObject) obj).getId(); // you need to refine this
}
public int hashCode() {
return name.hashCode();
}
List<ContactObject> listContacts = new ArrayList<ContactObject>();
//populate...
//LinkedHashSet preserves the order of the original list
Set<ContactObject> unique = new LinkedHasgSet<ContactObject>(listContacts);
listContacts = new ArrayList<ContactOjbect>(unique);
Use Set's instead.
Set's works as an Mathematical collection, so it doesn't allow duplicated elements.
So it checks the equality and the .equals() methods for each element each time you add an new element to it.

Categories

Resources