Skip to main content

Hasher and Equater as parallel to Comparator?

12 replies [Last post]
jahlborn
Offline
Joined: 2006-04-15

Something that's always bothered me about java is that the sortable maps can take a Comparator to customize the comparison, separate from the objects themselves, but HashMap (and the rest) cannot easily modify hashCode/equals. I propose adding these two interfaces to java. Their usage could be very widespread.

public interface Equater {
public boolean equals(Object o1, Object o2);
}

public interface Hasher extends Equater {
public int hashCode(Object o);
}

The Hasher would be for the HashMap/HashSet what the Comparator is for the TreeMap/TreeSet. And, if you really wanted to get crazy, Lists could take an Equater which would be used in methods like remove().

I think this would make the collections much more flexible and remove the need for custom value types used only to change how objects are mapped in a HashMap.

Example (current):

public class Foo {
public String firstName;
public String lastName;
public long timeStamp;
// equals/hashCode are based on
// firstName,lastName,timeStamp
}

// if you want to create a "set" based on
// firstName/lastName only
public class FooKey {
public String firstName;
public String lastName;
}

// firstName/lastName "set"
HashMap fooMap;

// add new Foo with newer timestamp
Foo newerObj;
FooKey newerObjKey = new FooKey(newerObj.firstName, newerObj.lastName);
fooMap.put(newerObjKey, newerObj);

Example (proposed):

// if you want to create a "set" based on
// firstName/lastName only
Hasher nameHasher = new Hasher() {
// implement equals/hashCode based on Foo
// firstName/lastName only
}
HashSet fooSet = new HashSet(nameHasher);

// add new Foo with newer timestamp
Foo newerObj;
fooSet.add(newerObj);

As you can see, instead of simulating a "Set" using a Map with a custom key type, you can instead customize the equals/hashCode used by the HashSet and remove the need for the extraneous key class.

Thoughts?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
tschodt
Offline
Joined: 2005-08-16

> You can't even subclass
> HashMap and override the key hash and equality
> methods.

HashMap is not responsible for implementing hashCode() and equals() on the objects used as keys.

> You have to start from scratch if you want a
> hash map from, say, byte[] to anything.

You can create a wrapper class that encapsulates byte[]
and implement hashCode() and equals() as you see fit.

mernst
Offline
Joined: 2005-02-19

> HashMap is not responsible for implementing
> hashCode() and equals() on the objects used as keys.

That is entirely debatable. If it weren't for HashMaps why would objects have a hashcode in the first place? This entire thread demonstrates that hashCode and equals might not have been the best choice to put into java.lang.Object in the first place. It's HashMap that wants a hash for an object and it might as well offer a way to customize that algorithm.

> You can create a wrapper class that encapsulates
> byte[] and implement hashCode() and equals() as you see
> fit.

While I can do that it's unnecessarily inefficient. It only pays off when the repeated calculation of the hashcode is too expensive - CollationKey as an example.

Would you have opposed the introduction of Comparator and its use in SortedList et al for the same reasons? Would you recommend people wrap Strings in CaseIgnoringWhenComparingStringWrapper instances instead of using String.CASE_INSENSITIVE_ORDER?

Matthias

jetbrains
Offline
Joined: 2005-12-15
mernst
Offline
Joined: 2005-02-19

> Just take a look below tutorial

So? That page doesn't even contain the words 'equal' or 'hashCode'.

mernst
Offline
Joined: 2005-02-19

I would so support that. You can't even subclass HashMap and override the key hash and equality methods. You have to start from scratch if you want a hash map from, say, byte[] to anything.

jahlborn
Offline
Joined: 2006-04-15

Not sure what to do next here. Do I just go ahead and create a bug for this suggestion and see if anybody works on it?

leouser
Offline
Joined: 2005-12-12

you could do that and you could also in addition write it yourself and send it to the Collaboration project:
https://jdk-collaboration.dev.java.net/

leouser

jahlborn
Offline
Joined: 2006-04-15

This has now become an RFE, vote for it here:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6435963

jahlborn
Offline
Joined: 2006-04-15

Note, Hasher and Equater would be appropriately genericized:

public interface Equater {
public boolean equals(T o1, T o2);
}

public interface Hasher extends Equater {
public int hashCode(T o);
}

alexlamsl
Offline
Joined: 2004-09-02

When I need this kind of functionality I'd normally write a quick (inner class) wrapper and everything will be sorted.

Since equals() and hashCode() belongs to Object, I think my solution is already clean enough.

jahlborn
Offline
Joined: 2006-04-15

actually, the proposal has nothing to do with sorting. HashMap/Set's cannot really be used for sorting anyway. Maybe my subject was a bit misleading. I didn't mean a parallel to Comparator in terms of sorting, more as a way of modifying how the collection works. Hasher would be a way of modifying "equality" as you would desire for the given HashMap/Set similar to how Comparator modifies the sorting behavior of a TreeMap/Set.

alexlamsl
Offline
Joined: 2004-09-02

Hmmm.... when I say "everything is sorted" I mean things are going alright - sorry for using a confusing english expression :-P