Will
Will

Reputation: 75673

Get an item from a Java Set

I have a Set of expensive objects.

These objects have IDs and the equals uses these IDs for equality.

These objects' type has two constructors; one for the expensive object, and one that just sets the ID.

So I can check if a particular ID is in the Set using Set.contains(new Object(ID)).

However, having determined the object is in the set, I cannot get the object instance in the set.

How can I get the exact object that the set contains?

Upvotes: 7

Views: 4757

Answers (5)

Donald Raab
Donald Raab

Reputation: 6706

Consider using the UnifiedSet class in Eclipse Collections. It implements the Pool interface in addition to Set. Pool adds Map-like API for put and get. Pool is more memory efficient than Map since it doesn't reserve memory for values, only keys.

UnifiedSet<Integer> pool = UnifiedSet.newSet();

Integer integer = 1;
pool.add(integer);

Assert.assertSame(integer, pool.get(new Integer(integer)));

Note: I am a committer for Eclipse Collections.

Upvotes: 4

tomosius
tomosius

Reputation: 1429

Here is one hack you can do to get what you want. Basically when you use contains to search within a hashset, the equals method of the object you're looking for will be called when hash codes match. Assuming you're dealing with objects of your own, or ones you can extend, it's trivial to set a 'beacon signal' ;) static field of the class with the reference that was just equated. And here you go, you can call contains and if true is returned, retrieve the object ;)

P.S. don't judge me

import java.util.HashSet;
import java.util.Set;

public class BecauseWhyNot {

    public static void main(String[] args) {

        Set<Poop> sewage = new HashSet<Poop>();

        set.add(new Poop("Morning Delight"));
        set.add(new Poop("Hangover Doodle"));

        System.out.println("Contains Fire Drill?: "
            + set.contains(new Poop("Fire Drill")));
        System.out.println("Contains Morning Delight?: "
            + set.contains(new Poop("Morning Delight")));

        if (Poop.lastlySmelled != null)
            System.out.println("It's you lucky day: " + Poop.lastlySmelled);
        else
            System.out.println("Sorry, try again ;)");
    }

    public static class Poop {
        static Poop lastlySmelled = null;

        String description;

        Poop(String desc) {
            description = desc;
        }

        @Override
        public int hashCode() {
            return 900913 * description.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            lastlySmelled = (Poop) this;
            if (this == obj)            return true;
            if (obj == null)            return false;
            if (getClass() != obj.getClass())   return false;
            Poop other = (Poop) obj;
            if (description == null) {
                if (other.description != null)
                    return false;
            } else if (!description.equals(other.description))
                return false;
            return true;
        }

        public String toString() {
            return "Poop: " + description + "!";
        }
    }

Upvotes: 1

David Grant
David Grant

Reputation: 14243

You could use a FilterIterator from Apache Commons Collections:

Predicate eq = new EqualPredicate(new Object(ID));
FilterIterator filter = new FilterIterator(set.iterator(), eq);
Object o = (Object) filter.next();

Obviously this is going to be an expensive way of accessing it, but if you're fixed on using a Set, you will have to iterate it at some point.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533820

If you want to get from a collection you should use a Map.

(Note most Set implementations are wrappers for a Map)

Map<Key, Value> map = new ....

Value value = map.get(new Key(ID));

In your case, the key and value can be the same type but that is generally a bad idea as keys, like elements of a set, should be immutable.

Upvotes: 6

Denis Tulskiy
Denis Tulskiy

Reputation: 19187

If HashMap with id's as keys wouldn't work, then I'd use a HashMap with your object both as key and value.

Upvotes: 2

Related Questions