Jayesh Dhandha
Jayesh Dhandha

Reputation: 2119

How to maintain same hashcode even though ordering of object change in List in Java?

Class A {
   private String test1;
   private String test2;
}

Class Feature {
   private List<A> obj;

   /* 
    HashCode which should return same value even though i change ordering of objects in List
   */
}

Current behaviour:

> List<A> contains [obj1, obj2, obj3] -> Some hashCode (Ex: 9058203945)
> List<A> contains [obj2, obj1, obj3] -> Some other hashCode (Ex:-23423423)

What i want is my hashCode of List should be same if i change the ordering of elements in List.

Any help?

Thanks in Advance

Upvotes: 4

Views: 2610

Answers (1)

Basil Bourque
Basil Bourque

Reputation: 338775

Not sure, but I guess you are referring to the List#hashCode method.

Ordering of elements is the very definition of List

The order of the elements contained in a List is the core concept of a list. So changing the order results in another list altogether. Those two lists are not conceptually equal, so they do not, and should not, return the same hash value (except by freak coincidence, which is exceedingly rare if using decent hash function).

Technically you could subclass a List class and override the hashCode method. You could do whatever you like in your own hashCode method. But this would be a very bad idea as it violates the semantics of a List.

Set

If you do not care about the order of your elements, use another collection instead of List.

Set is likely what you need. A Set holds a bunch of objects, not necessarily in any particular order. Some implementations iterate in a certain order, some do not promise any order.

Set < DayOfWeek > setX = Set.of( DayOfWeek.TUESDAY , DayOfWeek.WEDNESDAY );
Set < DayOfWeek > setY = Set.of( DayOfWeek.WEDNESDAY , DayOfWeek.TUESDAY );

boolean sameHashCode = ( setX.hashCode() == setY.hashCode() );

System.out.println( "setX.hashCode() = " + setX.hashCode() );
System.out.println( "setY.hashCode() = " + setY.hashCode() );
System.out.println( "sameHashCode = " + sameHashCode );

When run.

setX.hashCode() = -838114520

setY.hashCode() = -838114520

sameHashCode = true

This works across different implementations of Set.

Set < DayOfWeek > setX =new TreeSet<>() ;
setX.add( DayOfWeek.TUESDAY);
setX.add( DayOfWeek.WEDNESDAY);

Set < DayOfWeek > setY = new HashSet <>();
setY.add( DayOfWeek.WEDNESDAY );
setY.add( DayOfWeek.TUESDAY );

boolean sameHashCode = ( setX.hashCode() == setY.hashCode() );

sameHashCode = true

Those were enum objects above. Does it work with String objects? Yes.

Set < String > setX = new TreeSet <>();
setX.add( "Alice" );
setX.add( "Bob" );
setX.add( "Carol" );

Set < String > setY = new HashSet <>();
setY.add( "Bob" );
setY.add( "Alice" );
setY.add( "Carol" );

boolean sameHashCode = ( setX.hashCode() == setY.hashCode() );

sameHashCode = true

Set is distinct

Be aware of one major difference between Set and List:

  • List allows duplicates. One object can be added to the list multiple times, and take multiple slots in that list.
  • Set forbids duplicates. A Set is distinct, holding only a single reference to any particular object. Adding one particular object multiple times has no effect after the first time.

To quote the Set Javadoc:

A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. As implied by its name, this interface models the mathematical set abstraction.

Set < String > setY = new TreeSet <>();
setY.add( "Jan" );
setY.add( "Marsha" );
setY.add( "Marsha" );
setY.add( "Marsha" );
setY.add( "Cindy" );

setY.toString(): [Cindy, Jan, Marsha]

SequencedCollection

By the way, Java 21 brought sequenced collections. See JEP 431: Sequenced Collections.

The more general super-interface of both List and NavigableSet/SortedSet is SequencedCollection.

SequencedCollection < Integer > sequence = List.of( 42 , 7 , 99 ) ;  

Upvotes: 8

Related Questions