使 Hamcrest 匹配 Map 中的键或值

问题描述

我为 Hamcrest 和 Map 编写了这个测试程序,以使用 Hamcrest Matchers。 这个程序使用 Hamcrest 作为独立的(不使用 JUnit)。 为什么没有一个输出为真(匹配)? 如何修改此测试程序,以便匹配 Map 中的键或值(输出为真)?


    import java.util.Map;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    import org.hamcrest.Matchers;
    import org.hamcrest.collection.IsMapContaining;
    
    public class TestMap {
    
        public static void main(String[] args) {
        
            Map<String,Integer> map = Stream.of(new Object[][] { 
                { "data1",1 },{ "data2",2 },}).collect(Collectors.toMap(data -> (String) data[0],data -> (Integer) data[1]));
    
            for (Map.Entry<String,Integer> entry : map.entrySet()) {
                System.out.println("Matchers.hasKey(\"data1\") " + Matchers.hasKey("data1").matches("data1"));
                System.out.println("Matchers.hasValue(1) " + Matchers.hasValue(1).matches(1));
                System.out.println("IsMapContaining.hasKey(\"data1\") " + IsMapContaining.hasKey("data1").matches("data1"));
                System.out.println("IsMapContaining.hasValue(1) " + IsMapContaining.hasValue(1).matches(1));
                System.out.println("IsMapContaining.hasEntry(entry.getKey(),entry.getValue()) " + IsMapContaining.hasEntry(entry.getKey(),entry.getValue()));
            }
        }
    }

输出为:

Matchers.hasKey("data1") false
Matchers.hasValue(1) false
IsMapContaining.hasKey("data1") false
IsMapContaining.hasValue(1) false
IsMapContaining.hasEntry(entry.getKey(),entry.getValue()) map containing ["data2"-><2>]
Matchers.hasKey("data1") false
Matchers.hasValue(1) false
IsMapContaining.hasKey("data1") false
IsMapContaining.hasValue(1) false
IsMapContaining.hasEntry(entry.getKey(),entry.getValue()) map containing ["data1"-><1>]

解决方法

我只会解释第一个,其余的你可以自己理解(顺便说一句,这不完全是你的错)。

你认为这里会发生什么:

Matchers.hasKey("data1").matches("data1")

让我们阅读 hasKey 的文档:

当检查的 java.util.Map 包含至少一个等于指定键的键时,为 java.util.Map 的匹配创建匹配器。

现在,让我们阅读 matches 的文档:

这个方法匹配Object,而不是泛型类型T。这是因为Matcher的调用者在运行时不知道类型是什么(因为Java泛型的类型擦除)。 检查正确的类型取决于实现

理想情况下,您希望 编译器 (javac) 只允许您在 Map 中指定 matches(而不是 "data1" 字符串) .毕竟,您确实说过要比较 hasKeyMap,不是吗?但正如文档中所说:“检查正确的类型取决于实现”,javac 不能简单地做到这一点(这是一个限制);你需要自己做。

简单来说,这个 Matchers.hasKey("data1").matches("data1") 甚至不应该编译,但是因为这是 javac 的工作方式(并且因为 hamcrest 像这样设计了他们的代码),这确实可以编译,使用类型错误。

解决方案很简单:

System.out.println("Matchers.hasKey(\"data1\") " + Matchers.hasKey("data1").matches(map));

注意 matches(map)...