contains with ObservableList () returns always false

414 Views Asked by At

im using ObservableList in my JavaFX code , i'm trying to test if an object exists in this list but it always returns false even for those already existing in it . here is my code :

private ObservableList<OMission> UserMission = FXCollections.observableArrayList();    

OMission OM1 = new OMission(1,"user_firstname","user_lastname");


UserMission.add(OM1);



if(UserMission.contains(new OMission(1,"user_firstname","user_lastname")){

System.out.println("true");}

else {

System.out.println("false");

}

I was expecting to get "true" but im always getting false

what's happening ?

2

There are 2 best solutions below

0
Basil Bourque On BEST ANSWER

You likely neglected to implement the crucial Object overrides for equals and hashCode.

This issue is not specific to the OpenJFX class ObservableList. Any collection (list, set, map, etc.) that performs comparisons will depend on you writing an appropriate override for at least equals & possibly hashCode too. (Tip: Always override both or neither, never one alone.)

Below is example code using a modified version of your code. By the way, you were missing a right-paren. Also, life is easier if you follow the Java naming conventions.

For brevity, we use the new records feature in Java 16+. A record is a briefer way to write a class whose main purpose is to communicate data transparently and immutably. You merely need to declare the type and name of each member field. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString. Those last three methods by default examine each and every member field‘s value.

For simplicity we declared the record locally. You can just as well declare it nested or separate.

package work.basil.example;

import javafx.collections.*;

public class App {
    public static void main ( String[] args ) {
        System.out.println ( "Hello World!" );
        App app = new App ();
        app.demo ();
    }

    private void demo () {
        record Person( int id , String firstName , String lastName ) { }

        ObservableList < Person > UserMission = FXCollections.observableArrayList ();
        Person p1 = new Person ( 1 , "Alice" , "Anderson" );
        UserMission.add ( p1 );
        if ( UserMission.contains ( new Person ( 1, "Alice" , "Anderson" ) ) ) {
            System.out.println ( "true" );
        } else {
            System.out.println ( "false" );
        }
    }
}

When run.

Hello World!

true

If working with earlier versions for Java, or if a record is not appropriate to your situation, write a class similar to the following. Notice the methods equals & hashCode.

package work.basil.example;

import java.util.Objects;

public final class Person {
    private final int id;
    private final String firstName;
    private final String lastName;

    public Person ( int id , String firstName , String lastName ) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public int id () { return id; }

    public String firstName () { return firstName; }

    public String lastName () { return lastName; }

    @Override
    public boolean equals ( Object obj ) {
        if ( obj == this ) return true;
        if ( obj == null || obj.getClass () != this.getClass () ) return false;
        var that = ( Person ) obj;
        return this.id == that.id &&
                Objects.equals ( this.firstName , that.firstName ) &&
                Objects.equals ( this.lastName , that.lastName );
    }

    @Override
    public int hashCode () {
        return Objects.hash ( id , firstName , lastName );
    }

    @Override
    public String toString () {
        return "Person[" +
                "id=" + id + ", " +
                "firstName=" + firstName + ", " +
                "lastName=" + lastName + ']';
    }
}

The issue of overriding equals/hashCode has been covered many many times already. Search to learn more.

0
jewelsea On

Basil concurrently updated his answer to include some additional info while I was writing this. So, some info is duplicated in this answer. Please forgive any duplication here. I'll just leave this answer as-is for now.


To supplement Basil's answer, some different solutions are:

  1. Write custom implementations of equals and hashcode.

For OMission, implement equals(Object obj) (and probably best to have hashCode() implemented too).

You will end up with code like in Basil's example answer.

You can code these methods yourself from scratch, however, I don't recommend that. It is too easy to make needless, silly mistakes when coding these functions by hand.

  1. Use an IDE to auto-generate implementations of equals and hashcode.

Most IDEs have a menu item or shortcut to autogenerate these methods (see how to do this in Idea). This is how I normally generate these functions. If I add or remove a field to the class, then I delete the previous auto-generated functions and auto-generate new ones.

  1. Use a 3rd party library to generate equals and hashcode.

A third-party library, such as Lombok, can be used to autogenerate the methods. Lombok will do this via annotations, e.g. just add the annotation @EqualsAndHashcode to your class definition.

  1. Make OMission a record instead of a class.

If it is appropriate that the data can be represented as an immutable record rather than a class, then this is a recommended approach. It will not be appropriate for all data types.

By default, records implement appropriate equals and hashcode methods.

record OMission(
    int missionNum, 
    String firstname, 
    String lastname
) {}