4mac07
4mac07

Reputation: 63

Java - Groovy: Map with Objects as Key

I am having trouble on how to retrieve the Value from a Map indexed with custom Objects. In my case I have a Map with a Model object as Key and a List of objects as Value. The Map seems to be well populated because I've iterated through each Key and printed all Model objects to console.

My question is how to get Value from a specific entry in the Map.

Map<Model, Parameter> mapSet = m.getMyMap()

for(Entry<Model, Parameter> entry : mapSet){
    println entry.key.getModel() //prints each Model
}

List<Parameter> testListBase = mapSet.get(new Model("BASE"))

List<Parameter> testListSearch = mapSet.get(new Model("SEARCH"))

Do I have to override hashCode() and equals() from Object to retrieve the list for that entry in the Map?

UPDATE

Here it is the simple Model object, but still cannot retrieve the key using

mapSet.get(new Model("BASE"))

public final class Model {

private final String model;
private final static int count = 0;
private int id;

private Model(String model){
    this.model = model;
    id = ++count;
}

private String getModel(){
    return model;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + id;
    result = prime * result + ((model == null) ? 0 : model.hashCode());
    return result;
}

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

}

Upvotes: 2

Views: 3287

Answers (1)

Emmanuel Rosa
Emmanuel Rosa

Reputation: 9895

Yes, Model must implement hashCode() and equals(Object).

...great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map. - http://docs.oracle.com/javase/7/docs/api/java/util/Map.html

You may be able to implement hashCode() and equals(Object) quite easily using Groovy's EqualsAndHashCode AST transformation. Here's a working example:

@groovy.transform.TupleConstructor
@groovy.transform.EqualsAndHashCode
class Model {
    String name
}

@groovy.transform.TupleConstructor
class Parameter {
    String name
}

Map<Model, List<Parameter>> mapSet = [
    (new Model('BASE')): [
        new Parameter('Some parameter'), 
        new Parameter('Another parameter')
    ],

    (new Model('SEARCH')): [
        new Parameter('Yet another parameter'), 
        new Parameter('And yet another parameter')
    ]
]

for(Map.Entry<Model, List<Parameter>> entry: mapSet) {
    println entry.key // Prints each Model
}

List<Parameter> testListBase = mapSet.get(new Model("BASE"))
List<Parameter> testListSearch = mapSet.get(new Model("SEARCH"))

assert testListBase*.name.containsAll(['Some parameter', 'Another parameter'])
assert testListSearch*.name.containsAll(['Yet another parameter', 'And yet another parameter'])

I used the TupleConstructor AST for convenience, but the work-horse here is EqualsAndHashCode. Note that I assumed your intention and therefore deviated from your example to code what you said:

...a Map with a Model object as Key and a List of objects as Value.

The EqualsAndHashCode documentation describes how to tweak the default behaviour, in case you need to.

Upvotes: 4

Related Questions