Take the 2-minute tour ×

Why doesn't Set povide an operation to get an element that equals another element?

Set<Foo> set = ...;
Foo foo = new Foo(1, 2, 3);
Foo bar = set.get(foo);   // get the Foo element from the Set that equals foo

I can ask whether the Set contains an element equal to bar, so why can't I get that element? :(

To clarify, the equals method is overriden, but it only checks one of the fields, not all. So two Foo objects that are considered equal can actually have different values, that's why I can't just use foo.

share|improve this question
This post is already widely discussed, and good answers have been suggested. However if you're just looking for an ordered set, simply use SortedSet and its implementations, which are map-based (e.g. TreeSet allows for accessing first()). –  Eliran Malka Feb 10 at 15:08

10 Answers 10

up vote 28 down vote accepted

There would be no point of getting the element if it is equal. A Map is better suited for this usecase.

If you still want to find the element you have no other option but to use the iterator:

public static void main(String[] args) {

    Set<Foo> set = new HashSet<Foo>();
    set.add(new Foo("Hello"));

    for (Iterator<Foo> it = set.iterator(); it.hasNext(); ) {
        Foo f = it.next();
        if (f.equals(new Foo("Hello")))
            System.out.println("foo found");

static class Foo {
    String string;
    Foo(String string) {
        this.string = string;
    public int hashCode() { 
        return string.hashCode(); 
    public boolean equals(Object obj) {
        return string.equals(((Foo) obj).string);
share|improve this answer
There absolutely could be a point to getting the element. What if you wish to update some of the element's values after it has already been added to the Set? For example, when .equals() does not use all of the fields, as the OP specified. A less efficient solution would be to remove the element and re-add it with its values updated. –  KyleM Feb 19 '13 at 17:48
I would still argue that a Map is better suited (Map<Foo, Foo> in this case.) –  dacwe Feb 19 '13 at 20:48
I like this explanation... for some reason, I've never thought to use a Map like this. –  Justin Smith Oct 8 '13 at 19:04
@dacwe, I got here because I started looking for a way to avoid exactly that! An object that acts, at the same time, both as a key and corresponding value is exactly what a set should be all about. In my case, I'd like to get some complex object from a set by key (String). This String is encapsulated (and unique) to the object being mapped. In fact, the whole object 'revolves' around said key. Furthermore, the caller knows said String, but not the object itself; that's exactly why it wants to retrieve it by key. I'm using a Map now of course, but it remains odd behaviour. –  pauluss86 Jan 16 at 19:29

To answer the precise question "Why doesn't Set povide an operation to get an element that equals another element?", the answer would be: because the designers of the collection framework were not very forward looking. They didn't anticipate your very legitimate use case, naively tried to "model the mathematical set abstraction" (from the javadoc) and simply forgot to add the useful get() method.

Now to the implied question "how do you get the element then": I think the best solution is to use a Map instead of a set, to map the elements to themselves. In that way, you can efficiently retrieve an element from the "set", because the get() method of the map will find the element using an efficient hash table or tree algorithm. If you wanted, you could write your own implementation of set that offers the additional get() method, encapsulating the map.

The following answers are imho bad or wrong:

"You don't need to get the element, because you already have an equal object": the assertion is wrong, as you already showed in the question. Two objects that are equal still can have different state that is not relevant to the object equality. The goal is to get access to this state of the element contained in the set, not the state of the object used as a "query".

"You have no other option but to use the iterator": that is a linear search over a collection which is totally inefficient for large sets (ironically, internally the set is organized as hash map or tree that could be queried efficiently). Don't do it! I have seen severe performance problems in real-life systems by using that approach. Imho what is terrible about the missing get() method is not so much that it is a bit cumbersome to work around it, but that most programmers will use the linear search approach without thinking of the implications.

share|improve this answer
Great answer - maybe this should be the accepted one... –  molholm Nov 26 '13 at 21:05
Definetly the right answer! –  Koray Tugay Jan 23 at 7:12
meh. Overriding the implementation of equals so that non-equal objects are "equal" is the problem here. Asking for a method that says "get me the the identical object to this object", and then expect a non-identical object to be returned seems crazy and easy to cause maintenance problems. As others have suggested, using a map solves all of these problems: and it makes what you are doing self-explanatory. It's easy to understand that two non-equal objects might have the same key in a map, and having the same key would show the relationship between them. –  David Ogren Feb 10 at 22:27
Your criticism of my use of the word identical when I should have used the word equivalent is very valid. But defining equals on an object so that Foo and Bar are "equal" but are not "equal enough" for him to use them equivalently is going to create all kinds of problems both with both functionality and with readability/maintainability. This issue with Set just the tip of the iceberg for potential problems. For example, equal objects must have equal hash codes. So he's going to have potential hash collisions. Is it crazy to object calling .get(foo) specifically to get something other than foo? –  David Ogren Feb 27 at 14:47
It is probably worth noting that, e.g., HashSet is implemented as a wrapper around a HashMap (that maps the keys to a dummy value). So, using a HashMap explicitly instead of a HashSet would not cause overhead in the memory use. –  Alexey B. Jun 19 at 23:20

Quick helper method that might address this situation:

<T> T onlyItem(Collection<T> items) {
    if (items.size() != 1)
        throw new IllegalArgumentException("Collection must have single item; instead it has " + items.size());

    return items.iterator().next();
share|improve this answer
Thanks, exactly what i was looking for :) –  Shirane85 Dec 19 '13 at 7:43
Object objectToGet = ...
Map<Object, Object> map = new HashMap<Object, Object>(set.size());
for (Object o : set) {
    map.put(o, o);
Object objectFromSet = map.get(objectToGet);

If you only do one get this will not be very performing because you will loop over all your elements but when performing multiple retrieves on a big set you will notice the difference.

share|improve this answer

You better use the Java HashMap object for that purpose http://download.oracle.com/javase/1,5.0/docs/api/java/util/HashMap.html

share|improve this answer

I know, this has been asked and answered long ago, however if anyone is interested, here is my solution - custom set class backed by HashMap:


You can easily implement all other Set methods.

share|improve this answer
It's preferred to include the example instead of just linking to one. –  cpburnz Feb 10 at 22:34

If you have an equal object, why do you need the one from the set? If it is "equal" only by a key, an Map would be a better choice.

Anyway, the following will do it:

Foo getEqual(Foo sample, Set<Foo> all) {
  for (Foo one : all) {
    if (one.equals(sample)) {
      return one;
  return null;
share|improve this answer

Because any particular implementation of Set may or may not be random access.

You can always get an iterator and step through the Set, using the iterators' next() method to return the result you want once you find the equal element. This works regardless of the implementation. If the implementation is NOT random access (picture a linked-list backed Set), a get(E element) method in the interface would be deceptive, since it would have to iterate the collection to find the element to return, and a get(E element) would seem to imply this would be necessary, that the Set could jump directly to the element to get.

contains() may or may not have to do the same thing, of course, depending on the implementation, but the name doesn't seem to lend itself to the same sort of misunderstandings.

share|improve this answer
Anything the get() method would do is already being done by the contains() method. You can't implement contains() without getting the contained object and calling its .equals() method. The API designers seemed to have no qualms about adding a get() to java.util.List even though it would be slow in some implementations. –  Bryan Rink Oct 25 '13 at 22:14
I don't think this is true. Two objects can be equal via equals, but not identical via ==. If you had object A, and a set S containing object B, and A.equals(B) but A != B and you wanted to get a reference to B, you could call S.get(A) to get a reference to B, assuming you had a get method with the semantics of List's get method, which is a different use case than checking if S.contains(A) (which it would). This isn't even that rare a use case for collections. –  Tom Tresansky Nov 1 '13 at 15:21

Maybe using an array:

ObjectClass[] arrayName = SetOfObjects.toArray( new ObjectClass[setOfObjects.size()] );

share|improve this answer

If your set is in fact a NavigableSet<Foo> (such as a TreeSet), and Foo implements Comparable<Foo>, you can use

Foo bar = set.floor(foo); // or .ceiling
if (foo.equals(bar)) {
    // use bar…

(Thanks to @eliran-malka’s comment for the hint.)

share|improve this answer

Your Answer


