1

Why does ts.contains(t) return false and how can I fix it? Have a look at my code, please:

class MyList {
    private String x;

    public MyList (String x) {
        this .x = x;
    }

    public String toString () {
        return x;
    }   

    public static void main ( String [] args ) {
        List<MyList> ts = new ArrayList<MyList>();
        ts.add (new MyList ("one"));
        ts.add (new MyList ("two"));
        ts.add (new MyList ("three"));

        MyList t = new MyList("one");
        System.out.println ("Is t in ts? " + ts.contains(t));
    }
}

Thank you all for the help. Both SamzSakerz and michaeak answers work correctly.

Will
  • 33
  • 1
  • 4

4 Answers4

5

Just implement the equals() method:

class MyList {
    private String x;

    public MyList (String x) {
        this .x = x;
    }

    @Override
    public String toString () {
        return x;
    }   


    public static void main ( String [] args ) {
        List<MyList> ts = new ArrayList<MyList>();
        ts.add (new MyList ("one"));
        ts.add (new MyList ("two"));
        ts.add (new MyList ("three"));

        MyList t = new MyList("one");
        System.out.println ("Is t in ts? " + ts.contains(t));
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((x == null) ? 0 : x.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;
        }
        MyList other = (MyList) obj;
        if (x == null) {
            if (other.x != null) {
                return false;
            }
        } else if (!x.equals(other.x)) {
            return false;
        }
        return true;
    }
}

Output Is t in ts? true

The equals() Method is defined for the class Object which is the top class for every class. The contains() Method contractually checks, if the requested object a is contained in the list (i.e. same object is contained in a list) or if an equal object b (i.e. a.equals(b) is true) is contained in the list.

For List.contains(obj) the hashCode method is not required to be implemented, however, it is recommended to implement hashCode() whenever you implement equals() and make sure to depend on the same attributes in both methods.

michaeak
  • 1,548
  • 1
  • 12
  • 23
  • Not the downvoter but I have provided an answer that overrides `equal` and `hashcode` in 1 line. You don't really need that mess of if statements. – SamHoque Dec 12 '18 at 07:44
  • 1
    Actually it is not necessary to write a single line, this kind of code is generated, in eclipse e.g. Right click in the class source code and choose `Source` -> `Generate hashCode() and equals()...`, then select the attributes to check for them and press ok. – michaeak Dec 12 '18 at 07:47
  • Oh Thats neat, I don't use eclipse, I prefer intelliJ :p – SamHoque Dec 12 '18 at 07:48
  • Well, even IntelliJ is able to generate that piece of source code. Check https://www.jetbrains.com/help/idea/generate-equals-and-hashcode-wizard.html – michaeak Dec 12 '18 at 07:49
  • 1
    Waste of time to write it yourself, and error prone – michaeak Dec 12 '18 at 07:51
  • Not if you have done it multiple times before, But yeah I just tried to generate using the button it uses `Objects.hash` never knew that exists and the `equals` is 4 lines. instead of 1 line like my original answer – SamHoque Dec 12 '18 at 07:52
3

You have to override the equals and hashCode methods.

contains relies on equals, and the default implementation of equals is that its identity is compared. Then equals only returns true if it is the very same object.

In order to implement the equals method, you have to decide when two objects are considered equal. In your case, I assume that if the object's only field s is equal to the other, then you want them to be considered equal.

More:

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
2

You can check that list have object with specific property using

        System.out.println("Is t in ts? " + ts.stream().anyMatch(x -> x.x.equals("one")));
talex
  • 17,973
  • 3
  • 29
  • 66
1

Like others have pointed you need to override equals and hashcode we can do this in 1 line.

@Override
public int hashCode() {
    return toString().hashCode();
}

@Override
public boolean equals(Object obj) {
    return this == obj || obj != null && getClass() == obj.getClass() && toString().equals(obj.toString());
}

and now the output we get is

Is t in ts? true

Here is the full code:

import java.util.ArrayList;
import java.util.List;

class MyList {
    private String x;

    public MyList(String x) {
        this.x = x;
    }

    public static void main(String[] args) {
        List<MyList> ts = new ArrayList<MyList>();
        ts.add(new MyList("one"));
        ts.add(new MyList("two"));
        ts.add(new MyList("three"));

        MyList t = new MyList("one");
        System.out.println("Is t in ts? " + ts.contains(t));
    }

    @Override
    public String toString() {
        return x;
    }

    @Override
    public int hashCode() {
        return toString().hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return this == obj || obj != null && getClass() == obj.getClass() && toString().equals(obj.toString());
    }
}
SamHoque
  • 2,978
  • 2
  • 13
  • 43
  • Implementing `hashCode()` is not needed for using the `contains()` method, but it is recommended to do so. In this situation comparing the toString() works, but in other situations it might be wrong. – michaeak Dec 12 '18 at 08:02