【问题标题】:lambda expression vs static methodlambda 表达式与静态方法
【发布时间】:2017-10-30 01:27:32
【问题描述】:

我有一个关于没有代码重复的 lambda 表达式的可重用性的问题。例如,如果我有一个辅助方法,我可以轻松地将其编码为静态方法,并且可以从其他类中引用它而无需重复代码。这在 lambda 表达式中如何工作? 示例:我编写了以下静态方法

public class MyUtil {

    public static int doubleMe(int x) {
        return x * 2;
    }
}

我可以在整个项目的多个地方重复使用相同的方法,而无需重复代码

public class A {

    public void someOtherCalculation() {
        MyUtil.doubleMe(5);
    }
}

public class B {

    public void myCalculation() {
        MyUtil.doubleMe(3);
    }
}

当涉及到 lambda 函数时,它是如何工作的,编写一次函数并在多个类中使用相同的函数。

Function<Integer, Integer> doubleFunction = x -> x * 2;

在我的示例中,我将在哪里编写上述 lambda 函数以及如何在 A 类和 B 类中重用相同的函数?

【问题讨论】:

  • “代码重用”在这里是一个错误的目标。需要代码表现力。使用不“重用”代码的 lambda 有什么可能的危害,你有什么证据表明它没有?当许多不同的函子可以在算法中替代时,Lambdas 是适用的。你会为所有这些都写一个显式的静态方法,并为每个方法创建一个方法引用,这样你就可以说,“看,妈妈,我正在使用 lambdas!”?在这种情况下按惯例使用 lambda 不是更有意义吗?您寻求的真正工程效益是什么?
  • 如果要复用一个函数,那么定义一个实现Function接口的类。静态方法不是函数。

标签: java lambda functional-programming java-8 static-methods


【解决方案1】:

上面的 lambda 函数在哪里写

由于您的函数没有引用任何字段,因此将其放在静态最终字段中是合适的:

class Utility {
    public static final Function<Integer,Integer> doubleFunction = x -> x * 2;
}

如何在 A 类和 B 类中重复使用相同的内容?

您可以将其称为Utility.doubleFunction,并在需要它的上下文中传递它:

callMethodWithLambda(Utility.doubleFunction);

请注意,方法引用可以让您定义一个函数,并像使用 lambda 一样使用它:

class Utility {
    public static Integer doubleFunction(Integer x) {
        return x*2;
    }
}
...
callMethodWithLambda(Utility::doubleFunction);

这种方法非常灵活,因为它允许您在多个上下文中根据需要重用相同的代码。

【讨论】:

    【解决方案2】:

    确实,匿名函数适用于代码重用必要的情况。

    愚蠢的例子,但假设您使用map 为列表中的每个数字添加两个。如果这是您可能到处都需要的常见操作,那么将数字加二的静态函数比在任何地方编写相同的 lambda 更有意义。

    但是,如果您有一个将两个添加到列表中的函数,则将“添加两个”函数在本地定义为 lambda 会更有意义,这样您就不会使用其他任何地方都不需要的代码来插入您的类.

    在编写大量使用高阶函数的 Clojure 时,我创建本地匿名函数来整理我正在编写的“完整”函数中的代码是很常见的。这些匿名函数中的绝大多数在“全局”范围(或类范围)中都是无意义的;特别是因为它们通常对局部变量有闭包,所以它们无论如何都不能是全局的。

    【讨论】:

    • 我一直假设这一点,但从未在任何地方阅读过。很有帮助。
    【解决方案3】:

    使用 lambda 表达式,您无需担心可重用性(事实上,大多数 lambdas 根本没有被重用)。如果你想要一个 Function 指针指向这个方法,你可以像下面这样声明:

    Function<Integer, Integer> doubleFunction = MyUtil::doubleMe;
    

    并将其传递给任何方法或流以应用/映射,例如:

    public static void consume(Function<Integer, Integer> consumer, int value){
        System.out.println(consumer.apply(value));
    }
    
    public static void main(String[] args) throws Exception{
        Function<Integer, Integer> doubleFunction = MyUtil::doubleMe;
        consume(doubleFunction, 5);
    }
    

    【讨论】:

      【解决方案4】:

      与其他答案不同。我想用TDD的方式回答你的问题。

      如果您的doubleMe 就像您写的那样简单,那就是您应该停止滥用方法表达式引用,直接将其作为通用方法调用来调用。

      如果您的doubleMe 非常复杂,以至于您想测试doubleMe 独立,您需要通过依赖注入显式地制作隐式依赖,以测试它们是否可以通过它们的通信协议一起工作。但是java不能直接引用方法,除非您使用反射apiMethod/使用实现SAM接口的匿名类,该接口将请求委托给jdk-8之前的方法。令人高兴的是,您可以将方法表达式引用引用到 jdk-8 中的功能接口。所以你可以通过使用函数式接口使隐式依赖显式,然后我想写一些通信协议测试如下:

      @Test
      void applyingMultiplicationWhenCalculating???(){
          IntUnaryOperator multiplication = mock(IntUnaryOperator.class);
          B it = new B(multiplication);
      
          it.myCalculation();
      
          verify(multiplication).applyAsInt(3);
      }
      

      AND 那么你的类如B 应用的依赖注入更像如下:

      public class B {
          IntUnaryOperator multiplication;
      
          public B(IntUnaryOperator multiplication){
                this.multiplication = multiplication;
          }
      
          public void myCalculation() {
                multiplication.applyAsInt(3);
          }
      }
      

      那么您可以通过将方法表达式引用引用到功能接口来重用方法,如下所示:

      A a = new A(MyUtil::doubleMe);
      B b = new B(MyUtil::doubleMe);
      

      【讨论】:

        【解决方案5】:

        您可以执行以下操作。

        class Fn {
          public static final Function<Integer, Integer> X2TIMES = x -> x *2;
        }
        
        class Test {
          public static void main (String[] args) {
            System.out.println(Fn.X2TIMES.apply(5));
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2013-07-16
          • 2023-04-05
          • 1970-01-01
          • 2014-10-25
          • 2011-06-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多