代码之家  ›  专栏  ›  技术社区  ›  Eric Lilja

在Java中,如果函数值为函数,则变量值为

  •  3
  • Eric Lilja  · 技术社区  · 6 年前

    我必须处理一些JSON,它们的格式可能稍有不同(我只需要JSON数据的一个子集),我使用JSONPointer(来自Jackson)来查询JSON。我为这个问题写了一个非功能性的解决方案,这对我很有用,但是我想尝试一种功能性的方法来学习。在下面的测试程序中,您可以看到我的两个解决方案。它们都可以工作,但功能解决方案变得非常冗长,而且Intellij发出了一条烦人的警告,警告我在不进行ISpresent检查的情况下使用get()。我想看看如何改进功能实现的建议,我很高兴看到使用第三方库的解决方案。我想,这里的基本问题是如何建模if-else if-else,其中每个分支都应该以函数的方式返回一些值。

    @Test
    public void testIt() {
        ObjectMapper om = new ObjectMapper();
        ImmutableList.of(
                "{ \"foo\": { \"key\": \"1\" } }",
                "{ \"bar\": { \"key\": \"1\" } }",
                "{ \"key\": \"1\" }")
                .forEach(str -> {
                    try {
                        System.out.println("Non-functional: " + getNode(om.readTree(str)));
                        System.out.println("Functional: " + getNodeFunc(om.readTree(str)));
                    } catch (Exception e) {
                        throw new RuntimeException("", e);
                    }
                });
    }
    
    private JsonNode getNode(JsonNode parentNode) {
        JsonPointer jp1 = JsonPointer.compile("/foo");
        JsonPointer jp2 = JsonPointer.compile("/bar");
        if (!parentNode.at(jp1).isMissingNode()) {
            return parentNode.at(jp1);
        } else if (!parentNode.at(jp2).isMissingNode()) {
            return parentNode.at(jp2);
        }
        return parentNode;
    }
    
    private JsonNode getNodeFunc(JsonNode parentNode) {
        BiFunction<JsonNode, String, Optional<JsonNode>> findNode = (node, path) -> {
            JsonPointer jp = JsonPointer.compile(path);
            return node.at(jp).isMissingNode() ? Optional.empty() : Optional.of(node.at(jp));
        };
    
        return findNode.apply(parentNode, "/foo")
                .map(Optional::of)
                .orElseGet(() -> findNode.apply(parentNode, "/bar"))
                .map(Optional::of)
                .orElse(Optional.of(parentNode))
                .get(); // Intellij complains here: Optional.get() without isPresent check
    }
    
    2 回复  |  直到 6 年前
        1
  •  5
  •   Andrew    6 年前

    我会把它改写成

    private JsonNode getNodeFunc2(JsonNode parentNode) {
        return Stream.of(JsonPointer.compile("/foo"), JsonPointer.compile("/bar"))
                     .filter(i -> !parentNode.at(i).isMissingNode())
                     .findFirst()
                     .map(parentNode::at)
                     .orElse(parentNode);
    }
    

    private JsonNode getNodeFunc3(JsonNode parentNode) {
        return Stream.of(JsonPointer.compile("/foo"), JsonPointer.compile("/bar"))
                     .map(parentNode::at)
                     .filter(Predicate.not(JsonNode::isMissingNode))
                     .findFirst()
                     .orElse(parentNode);
    }
    

    private JsonNode getNodeFunc4(JsonNode parentNode) {
        return Stream.of("/foo", "/bar")
                     .map(JsonPointer::compile)
                     .map(parentNode::at)
                     .filter(Predicate.not(JsonNode::isMissingNode))
                     .findFirst()
                     .orElse(parentNode);
    }
    

    因为那块

    if (!parentNode.at(jp1).isMissingNode()) {
        return parentNode.at(jp1);
    } else if (!parentNode.at(jp2).isMissingNode()) {
        return parentNode.at(jp2);
    }
    

    是代码重复,可以通过循环灵活处理:

    for (JsonPointer jsonPointer : jsonPointers) {
        JsonNode kid = parentNode.at(jsonPointer);
        if (!kid.isMissingNode()) {
             return kid;
        }
    }
    
        2
  •  -2
  •   GoJoe    6 年前

    只是想一想, getNode 功能是完美的功能代码:

    • 输出仅取决于其输入参数和内部算法。
    • 它没有副作用(它不从外部世界读任何东西,也不向外部世界写任何东西)
    • 它总是从相同的输入返回相同的输出。