如何通过使用Java 8匹配Map中的键从JSON对象提取a值?

时间:2018-09-20 21:48:25

标签: json java-8 jackson

我正在使用Java 8和jackson尝试从json对象获取一个int值。这是我用来验证结构的一些类似代码。

HashMap<String, Object> myMap = new HashMap<String, Object>();  
myMap
        .entrySet()
        .stream()
        .forEach(x -> System.out.println(x.getKey() + " => " + x.getValue()));

和结果:

myKey1 => {“数字”:1}

myKey2 => {“数字”:1}

myKey3 => {“数字”:2}

我想做的是使用密钥,例如myKey1来找到json值,即{“ number”:1}并取出实际数字,该数字为1。

但是,我并不是所有人都知道密钥的值,只是我想匹配的密钥。因此,我必须动态地执行此操作。我知道这些值的结构,除了数字可以不同之外,它总是相同的。

我想是因为我不知道键及其顺序,再加上我正在使用entrySet,这迫使我不得不使用Optional,这使这变得更加困难。

这是我的代码,实际上我在其中使用该键来提取json值:

Optional<Object> object = myMap.entrySet().stream()
        .filter(e -> e.getKey().equals(myKey))
        .map(Map.Entry::getValue)
        .findFirst();

但是,流向后撤回

  

可选[{“数字”:1}]

而且我似乎无法弄清楚这个数字,所以我可以从一个方法中返回它。我其实不是 对于该对象有一个Java类,因此我认为这就是为什么它返回Optional的原因,因为我在没有它的情况下遇到了编译错误,但我不确定。

关于正确方法的任何想法吗?

3 个答案:

答案 0 :(得分:3)

为什么要遍历地图的所有条目并通过键进行线性搜索以获取条目的值?

只需直接获取值:

Object value = myMap.get(myKey);

现在,关于value中的数字,就像您说的那样,您没有一个表示地图值的类,最有可能的事情是您正在使用的JSON库正在创建每个值一个Map。因此,从现在开始,我们假设这些值实际上是Map的某种实现:

Integer = null;

if (value != null) {
    // What's the type of the value? Maybe a Map?
    if (value instanceof Map) {
        Map<String, Object> valueAsMap = (Map<String, Object>) value;
        number = (Integer) valueAsMap.get("number");
    }
}

我假设数字是Integer,但它们完全可以是Long实例,甚至是DoubleBigDecimal s。只需确保类型正确,即可确保第二次转换不会失败。


编辑:为了完整起见,这是值不是映射而是代表json节点的某些类的代码。在这里,我使用的是Jackson库中的JsonNode,但其他库的方法非常相似:

Integer = null;

if (value != null) {
    if (value instanceof JsonNode) {
        JsonNode valueAsNode = (JsonNode) value;
        number = (Integer) valueAsNode.get("number").numberValue();
    }
}

答案 1 :(得分:1)

findFirst()返回一个Optional。致电.get()后,您需要致电.orElse().orElseThrow()findFirst()

然后可以将Object强制转换为JsonNode并检索值。这是完整的代码:-

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    HashMap<String, Object> myMap = new HashMap<String, Object>();
    myMap.put("myKey1", mapper.readTree("{\"number\":1}"));
    myMap.put("myKey2", mapper.readTree("{\"number\":1}"));
    myMap.put("myKey3", mapper.readTree("{\"number\":2}"));

    System.out.println(getNumberUsingMapKey(myMap, "myKey3"));
}

private static int getNumberUsingMapKey(Map<String, Object> map, String key) throws Exception {
    return Optional.of(map.get(key))
            .map(o -> ((JsonNode) o).get("number").asInt())
            .get(); //or use one of the following depending on your needs
//                .orElse(-1);
//                .orElseThrow(Exception::new);
}

//or use this method
private static int getNumberUsingMapKeyWithoutOptional(Map<String, Object> map, String key) throws Exception {
    Object o = map.get(key);
    return ((JsonNode) o).get("number").asInt();
}

输出

2

答案 2 :(得分:0)

不幸的是,我从一开始就没有很好地描述我的问题陈述,但这是我能够从其他答案中得出的最终工作代码。

这是数据结构的样子。一个具有值的键,它是一个具有键和一个int的JSON对象,换句话说就是一个嵌套的JSON对象。

键:myKey1值:{“数字”:1}

键:myKey2值:{“数字”:1}

键:myKey3值:{“数字”:2}

我正在发布它,以防其他人遇到该用例。这可能不是最好的方法,但是可以。

      Object value = myMap.get(keyName);
      ObjectMapper mapper = new ObjectMapper();
      String jsonString = (String) value;
      JsonNode rootNode = mapper.readTree(jsonString);    
      JsonNode numberNode = rootNode.path("number");
      System.out.println("number: " + numberNode.intValue());

和结果:

  

数字:1