使用包含空字段的复合键读取Multimap

时间:2015-03-04 11:40:58

标签: java collections guava multimap

我有一个Multimap来存储一些带有复合键的数据(数据类型,数据ID)。 这是我的代码:

public class Data {

    private final String type;

    private final Integer id;

    private final String information;

    public Data(String type, Integer id, String information) {
        this.type = type;
        this.id = id;
        this.information = information;
    }

    @Override
    public String toString() {
        return "Type: " + type + ", ID: " + id + ", Info: " + information;      
    }

}

public class Test {

    private static Multimap<Key, Data> data = HashMultimap.create();

    static class Key {

        private final String type;

        private final Integer id;

        public Key(String type, Integer id) {
            this.type = type;
            this.id = id;
        }

        @Override
        public int hashCode() {
            //System.out.println("in hashcode");
            return Objects.hashCode(type);
        }

        @Override
        public boolean equals(Object obj) {
            //System.out.println("in equals");
            if (obj == null) {
                return false;
            }

            if (!(obj instanceof Key)) {
                return false;
            }

            Key other = (Key) obj;
            if (other.type.equals(type)) {
                if (other.id == null) {  // Return true for null ID Data
                    return true;
                } else if (other.id.equals(id)) {
                    return true;
                }
            }

            return false;
        }

    }

    private static void addData(String type, Integer id, String information) {
        data.put(new Key(type, id), new Data(type, id, information));
    }

    private static void printData(String type, Integer id) {
        System.out.println("\n===============");
        System.out.println("Filtered Data for: Type => " + type + ", ID => " + id);
        for (Data d : data.get(new Key(type, id))) {
            System.out.println(d);
        }
    }

    public static void main(String[] args) {
        addData("confidential", 11, "Some Confidential Data!");
        addData("private", 21, "Some Private Data!");
        addData("government", 13, "Some Govt. Data!");

        addData("public", null, "Some public data!");
        addData("public", 26, "Another public data!");
        addData("public", 4, "More public information!");

        addData("unspecified", null, "Lorem ipsum dolor sit amet!");
        addData("unspecified", 15, "consectetur adipiscing elit.");
        addData("unspecified", 25, "Integer sed velit vel.");
        addData("unspecified", null, "In vitae velit consequat");       

        printData("unspecified", 25);
        printData("public", 26);
    }

}

现在,我希望按Data::type&amp;过滤此数据。 Data::id,包括Data::type匹配但Data::idnull的数据。

预期输出:

===============
Filtered Data for: Type => unspecified, ID => 25
Type: unspecified, ID: null, Info: In vitae velit consequat
Type: unspecified, ID: null, Info: Lorem ipsum dolor sit amet!
Type: unspecified, ID: 25, Info: Integer sed velit vel.

===============
Filtered Data for: Type => public, ID => 26
Type: public, ID: null, Info: Some public data!
Type: public, ID: 26, Info: Another public data!

实际输出

===============
Filtered Data for: Type => unspecified, ID => 25
Type: unspecified, ID: null, Info: In vitae velit consequat
Type: unspecified, ID: 15, Info: consectetur adipiscing elit.
Type: unspecified, ID: null, Info: Lorem ipsum dolor sit amet!
Type: unspecified, ID: 25, Info: Integer sed velit vel.

===============
Filtered Data for: Type => public, ID => 26
Type: public, ID: 4, Info: More public information!
Type: public, ID: null, Info: Some public data!
Type: public, ID: 26, Info: Another public data!

为此,我实施了hashCode()&amp; equals()类中的Key方法,当其他数据对象trueid时返回null


问题:

  1. 我使用了正确的方法,还是可以使用简单的Map来实现?

  2. 为什么hashCode&amp;当我调用equals方法时,Multimap::get()方法只调用一次? (据我说,地图中的每个键都应该与指定的键匹配!)

  3. 如果方法正确,如何实施equals方法以获得预期结果?

1 个答案:

答案 0 :(得分:2)

为了使哈希映射正常工作,equals实现必须满足约束,如果a.equals(b)b.equals(c)那么a.equals(c)必须为真。如果你破坏了那个约束,那么地图将表现得不可预测。此属性称为传递性。请参阅equals implementation here上的约束的完整列表。

要执行您想要的操作,您必须在printData方法中执行两次查找,一次使用new Key(type, id),另一次使用new Key(type, null)。聪明的equals实现没有捷径。

要回答这个问题,为什么在致电hashCode时,您只看到equalsget()只召唤一次?这是对equals的约束的另一个结果。根据您的Key(x, 15)实施,地图已确定Key(x, null)equals相同。这是在插入数据时完成的。因此,在查找时,它只需要与其中一个进行比较,然后假设另一个也匹配。