Java - 递归获取地图的所有键

Java - Get all keys of a map recursively

所以目前我正在使用 SnakeYaml 开发一个 yml 文件更新程序,但是我有这个问题我不知道如何解决。

这是我的 class 获取 yaml 文件的所有键作为 Set:

public class YamlKeys {

    private static Set<String> keys = new HashSet<String>();
    private static String path = "";

    YamlKeys(Map<?, ?> data) {
        getKeysRecursive(data);
    }

    private void getKeysRecursive(final Map<?, ?> data) {
        for(Object key : data.keySet()) {
            final Object value = data.get(key);
            if(key instanceof String) {
                if(path.length() == 0) {
                    path = (String)key;
                } else {
                    path = path+"."+(String)key;
                }
            }
            if(value instanceof Map) {
                getKeysRecursive((Map<?, ?>) value);
            } else {
                keys.add(path);
                if(path.contains(".")) {
                    path = path.substring(0, path.lastIndexOf("."));
                }
            }
        }
        path = "";
    }

    Set<String> getKeys() {
        return keys;
    }
}

这是我的 yml 文件:

FirstKey:
  SecondKey:
    Enabled: true
    ID: "Some text"
    AnotherKey:
      AValue: true
    TestKey:
      TestValue: "More text"

我是这样称呼它的:

new YamlKeys(data).getKeys().stream().forEach(key -> System.out.println(key));

输出为:

FirstKey.SecondKey.AnotherKey.AValue
FirstKey.SecondKey.Enabled
FirstKey.SecondKey.ID
TestKey.TestValue

问题出在最后一个,因为它应该是“FirstKey.SecondKey.TestKey.TestValue”,但是前两个键由于路径重置而被删除,如果更多键被添加到“,则需要此路径重置” FirstKey”,但我不知道如何解决。

弹出 path 最后一部分的代码也应该在处理地图后应用:

if(value instanceof Map) {
    getKeysRecursive((Map<?, ?>) value);
} else {
     keys.add(path);
}
if(path.contains(".")) {
   path = path.substring(0, path.lastIndexOf("."));
}

此外,当您在 getKeysRecursive 末尾重置路径时,您将丢弃有关您在树中有多深的上下文。因此,当您的最深地图完成处理时,它会清除 path,但父地图尚未完成处理。

试图从递归调用中管理这个单个可变 path 变量的状态是很棘手的。这可以通过像这样传递路径来更好地完成:

private void getKeysRecursive(final Map<?, ?> data, String parentPath)

您也可以考虑使用集合,可能会清理一些围绕初始状态的 if-else 逻辑。

private void getKeysRecursive(final Map<?, ?> data, List<Object> parentPath) {
    for(Object key : data.keySet()) {
        List<Object> path = new ArrayList<>(parentPath);
        path.add(key);
        final Object value = data.get(key);
        if(value instanceof Map) {
            getKeysRecursive((Map<?, ?>) value, path);
        } else {
            keys.add(path.stream().map(Objects::toString).collect(Collectors.joining(".")));
        }
    }
}

并以 app.getKeysRecursive(data, Collections.emptyList());

开始