-1

I need to know that two objects have the same values for their parameters.

I do not know the type of object. That have the same values in their parameters, but may have different references.

Like:

Person person = new Person("Alfred", "00001" ...);
Person person2 = new Person("Alfred", "00001" ...);
list.add(person, person2);

Remeber I do not know the type of object, and i cant modify the object. Could be person, animal... or something different.

I need to know if when I iterate list, it has duplicate objects.

for (Object item : list) {

}

Ty.

AlberrB
  • 45
  • 2
  • 12
  • 1
    Compare: `o1.equals(o2)` - no duplicates: `new HashSet(list).size() == list.size()`. You'll have to implement `equals` and `hashCode` in your classes (if `Person` is given, you are ok). – giorgiga Feb 15 '18 at 08:24
  • Sorry, I need to eliminate repeated objects. – AlberrB Feb 15 '18 at 08:42
  • Read the [java docs for HashSet](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/HashSet.html) :) – giorgiga Feb 15 '18 at 08:47

4 Answers4

1

In Java 8(need to overrider hashCode() & equals(Object obj) methods):

cat c1=new cat("lolo", "black");
cat c3=new cat("lolo", "black");
List<Object> arrayList = new ArrayList<Object>();
arrayList.add(c1);
arrayList.add(c3);
List<Object> deduped = arrayList.stream().distinct().collect(Collectors.toList());

Old Java Versions:

If you want eliminate repeated objects use HashSet and must implement (override) hashCode() method:

public class cat {
    String name;
    String color;
    public cat(String name, String color) {
        super();
        this.name = name;
        this.color = color;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((color == null) ? 0 : color.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        cat other = (cat) obj;
        if (color == null) {
            if (other.color != null)
                return false;
        } else if (!color.equals(other.color))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    public static void main(String[] args) {
        cat c1=new cat("lolo", "black");
        cat c2=new cat("lolo2", "white");
        cat c3=new cat("lolo", "black");

        List<Object> arrayList = new ArrayList<Object>();
        arrayList.add(c1);
        arrayList.add(c3);

        Set<Object> uniqueElements = new HashSet<Object>(arrayList);
        arrayList.clear();
        arrayList.addAll(uniqueElements);
        System.out.println(arrayList.size());//will be 1

    }

}

If you need more information how to make good hashcode() you can read this answer:Best implementation for hashCode method

If all the object class implements (override) the equal() method it's ok to use it.

example:

public class cat {
    String name;
    String color;
    public cat(String name, String color) {
        super();
        this.name = name;
        this.color = color;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        cat other = (cat) obj;
        if (color == null) {
            if (other.color != null)
                return false;
        } else if (!color.equals(other.color))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
public static void main(String[] args) {
        cat c1=new cat("lolo", "black");
        cat c2=new cat("lolo2", "white");
        cat c3=new cat("lolo", "black");

        Object o1=c1;
        Object o2=c2;
        Object o3=c3;
        System.out.println(o1.equals(o2));//false
        System.out.println(o1.equals(o3));//true

    }

}
One Man Crew
  • 9,420
  • 2
  • 42
  • 51
  • What about the duplicates? This is just an example for a rather mediocre equals implementation. – Christian Feb 15 '18 at 08:35
  • @Christian you can compare them override the hashcode() method and you hashset to remove duplicates. – One Man Crew Feb 15 '18 at 08:48
  • I know. I just mentioned, that this was not part of your answer. Later you added the hashCode. Good. But actually writing hashCode and equals methods in the answer is rather superfluous. But I did not downvote. I hope you didn't either. – Christian Feb 15 '18 at 09:46
1

Possibility 1: equals()

In the simplest case equals() has been implemented in the class of the objects you want to compare, so that internal state is compared. In that case, you just have to call a.equals(b) (assuming a is not null) and call it a day.

Possibility 2: use reflection

If you cannot assume that equals() has been implemented in a way that suits you, it becomes a little more difficult. You should look for libraries that provide a deepEquals() operation, that will use reflection to look under the hood and compare the actual classes, and if equals the fields in both objects.

I'd advise using the EqualsBuilder class that is provided by Apache Commons Lang, as I've found it to work pretty well.

Do note that Objects.deepEquals(), that exists since Java 7 as far as I remember, does not actually perform a deep comparison according to its documentation, as it delegates the work to the first parameter's equals() method.

Of course, you can also implement a deepEquals() operation yourself, if you have the time and know or want to learn the Reflection API.

KevinLH
  • 328
  • 3
  • 10
1

I see are two ways, the preferred, Java-typical way using the equals() method, and a fragile, reflection-based way.

Using equals()

All decent Java classes should implement the equals() method, meant to compare two objects for having semantically the same contents. I guess that definition matches your requirement "the same values in their parameters" (it's not literally what you ask for, but for good reason - see below). Of course, this relies on the relevant classes having a proper equals() implementation, or you being able to add one to the relevant classes. Go that way if possible.

Using reflection

Disclaimer: Avoid that way if possible.

Java allows you to find the fields that a given class has, and to read out the value of such a field for a given instance. So you can:

  • Find the class of the first object.
  • Compare to the class of the second object, returning false if different.
  • Find the fields of the class.
  • Iterate over the fields, getting the field values of both objects.
  • Compare the field values (using the equals() method? Recursively using your reflection-based comparison? - you decide...).

Why a class-specific equals() method is better than a blind field-values comparison

Not all fields are created equal. Often, a class has internal fields that have nothing to do with an object property you'd want to compare when asking for property equivalence. Examples:

  • To make some computations faster, the instance caches some dependent data. Having the cache filled or empty technically is a different field value, but has no semantic meaning.
  • The instance maintains some lastAccess date. Technically, you'll get different values most of the time, but that doesn't mean that some relevant object property is different.

Blindly comparing object fields will always fall into the trap of comparing these fields as well, although they don't have that semantic meaning you'd expect.

Only the class itself knows which fields to usefully compare and which ones not. And that's why every class should have its own equals() method, and why that should be used for contents comparison.

Ralf Kleberhoff
  • 6,990
  • 1
  • 13
  • 7
  • I used reflection, thank you very much. – AlberrB Feb 15 '18 at 11:58
  • @downvoter: why? – Ralf Kleberhoff Feb 15 '18 at 13:12
  • @AlberrB Did you read all the suggestions? There it stands. Disclaimer: Avoid that way if possible. If this is homework, usage of reflection is just plain wrong. It would be in any project of mine. – Christian Feb 15 '18 at 14:43
  • Yes, your question would work if the object had the same reference, but it is not, I need to know if they are equal by the value of the arguments: List l1 = new ArrayList (); Person per = new Person (); per.setNam("s1"); per.setID ("1"); l1.add (per); Person per2 = new Person (); per2.setNam ("p2"); per2.setID("1"); l1.add (per2); Set set = new HashSet (l1) output: [Person @ 7852e922, Person @ 4e25154f] – AlberrB Feb 15 '18 at 16:37
  • If it only works in the case of same reference, then your implementation of equals and hashCode is not correct. Use a tool for generating those methods and learn from them. – Christian Feb 15 '18 at 18:16
0

Just implement for every class, which is possible in list, an appropriate equals and hashCode method.

Then convert the list to a set and compare the size of these two collections, and you will know if duplicates are in that list.

Set set = new HashSet(list);
if(set.size() == list.size()) {
  System.out.println("No duplicates.");
} else {
  System.out.println("Found duplicates.");
}
Christian
  • 3,503
  • 1
  • 26
  • 47