【问题标题】:Refactoring Java8 code with Functional Interface使用功能接口重构 Java8 代码
【发布时间】:2026-02-12 15:15:01
【问题描述】:

输入:

public BigDecimal getMaxValuation(ServiceData data) {
    System.out.println("getMaxValuation()");
    BigDecimal calculatedAmount;
    //4 String returnValue = getReturnValue(data);
    Function<ServiceData,String> returnValueFn = this::getReturnValue;
    BigDecimal orderSize = getOrderSize(returnValueFn.apply(data),60);
    Predicate<String> gasPredicate = "GAS"::equalsIgnoreCase;
    Predicate<String> oilPredicate = "OIL"::equalsIgnoreCase;
    if(gasPredicate.test(returnValueFn.apply(data)))
        calculatedAmount = callA(data.getValuation())
    else if(oilPredicate.test(returnValueFn.apply(data)))
        calculatedAmount = callB(data.getValuation())
    else
        calculatedAmount = callC(data.getValuation())
    return calculatedAmount;
}

public String getReturnValue(ServiceData data){
    System.out.println("getReturnValue()");
    return returnValue;
}   

在上述函数getMaxValuation()中,当我们注释第4行并将其替换为Function&lt;ServiceData,String&gt;时, getReturnValue() 在执行过程中被调用了 3 次。但是当我们取消注释第 #4 行并删除所有 Function&lt;ServiceData,String&gt; 相关更改 getReturnValue() 仅被调用一次。

当我们使用Function 时,有什么方法可以实现相同的行为吗?

【问题讨论】:

  • 不清楚你在问什么。在一种情况下,您调用该函数一次,在另一种情况下,您调用它 3 次。如果您只想使用Function 对象调用它一次,只需执行String returnValue = returnValueFn.apply(data);?
  • 调用function.apply 3次相当于调用getReturnValue(data) 3次。前面的评论者向您展示了如何调用该函数一次。如果我可能如此大胆,我不确定这些更改是否真的让您的新代码在比喻或字面上更具“功能性”..
  • @Atmas,谢谢。有什么建议可以将该代码更改为功能单元吗?
  • @MarkPeters,非常感谢您的建议!!
  • @busywithJava,内联解释太多了,可能超出了 SO 作为一个平台来解释这一切的范围。我鼓励您搜索一些介绍 Java 在线概念的好文章。有很多概念。如果您熟悉面向对象编程,请将其视为一个大概念。因此需要花费一些时间来检查、思考并实践它。不过,您走在正确的道路上。

标签: java java-8 functional-interface


【解决方案1】:

无论是直接调用方法还是使用函数式接口,调用一次并将结果存储在局部变量中以避免重复评估的逻辑都不会改变。

到目前为止,您将直接调用重写为函数式接口的使用本身看起来就像是结束了,实际上并没有改进任何东西,只是让代码变得更复杂。

使用函数式编程改进代码的一种方法是使用函数映射来通过单个查找替换 if-else 阶梯:

static final Map<String, Function<Valuation,BigDecimal>> METHOD;
static {
    Map<String, Function<Valuation,BigDecimal>> m
        = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    m.put("GAS", ContainingClass::callA);
    m.put("OIL", ContainingClass::callB);
    METHOD = Collections.unmodifiableMap(m);
}

public BigDecimal getMaxValuation(ServiceData data) {
    // don't know how to incorporate this, as it was entirely unused
    // BigDecimal orderSize = getOrderSize(getReturnValue(data), 60);

    return METHOD.getOrDefault(getReturnValue(data), ContainingClass::callC)
        .apply(data.getValuation());
}

其中Valuation指的是ServiceData.getValuation()的返回类型,ContainingClasscallAcallBcallC的声明类,假设static方法。

如果这些方法不是static,那么代码应该是这样的

static final Map<String, BiFunction<ContainingClass,Valuation,BigDecimal>> METHOD;
static {
    Map<String, BiFunction<ContainingClass,Valuation,BigDecimal>> m
        = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    m.put("GAS", ContainingClass::callA);
    m.put("OIL", ContainingClass::callB);
    METHOD = Collections.unmodifiableMap(m);
}

public BigDecimal getMaxValuation(ServiceData data) {
    return METHOD.getOrDefault(getReturnValue(data), ContainingClass::callC)
        .apply(this, data.getValuation());
}

【讨论】:

  • 非常感谢您提供如此详细的解释。