功能分解和currying的好处

时间:2017-01-10 07:53:59

标签: java functional-programming java-8

我有一个函数,在遗留代码中计算(字符串A,int B)

map.moveCamera(CameraUpdateFactory.newLatLngZoom(route.startLocation, 10));

在B上应用的计算取决于A的值。

在功能风格上,我可以将其分解为:

Double calculate(String A,int B) {
   if(A.equals("something")){  return B*1.02; }
   if(B.equals("some")) return B*1.0;
   else return B;
}

然后我会打电话给<{p>,而不是打电话给Function<String, Function<Integer,Double>> strategyA = (a)-> { if(A.equals("something")) return b -> b*1.02; if(B.equals("some")) return b -> return b -> b*1.0; else return b -> b; }

calculate(a,b)

第二种风格是否优于第一种风格。根据我的理解,这涉及战略模式和功能分解和Currying。

如果第二种方法确实更好,你会如何说服某人?

2 个答案:

答案 0 :(得分:3)

在Java中,提供命名代码的首选方法是保留方法。没有理由将方法表达为函数,只是为了具有“更多功能风格”。为什么函数支持被添加到Java中的原因是,您有时希望将对代码的引用传递给另一个方法或函数。在这种情况下,接收方法定义了所需的函数签名,而不是您要封装的代码。

因此,如果接收方法只想将ObjIntConsumer<String>String对传递给它,那么您的int方法可能会被称为(String,int) → Double,而不会对此感兴趣结果。否则,它可能使用表示BiFunction<String,Integer,Double>签名的自定义功能接口。或者当你接受拳击时,Function会这样做。

Currying允许您重用现有的接口,如{{1}}来表示具有多个参数的函数,当没有内置接口时,但给定生成的通用签名,这将至少出现在Java代码中的一个位置使用这样的curried函数,可读性受到很大影响,因此在大多数情况下,在大多数情况下,定义一个新的功能界面将比curry更受欢迎......

对于其他编程语言,对函数类型使用不同的语法和类型推断(或者首先使用实际函数类型,而不是在函数接口上设置),这将是完全不同的。

答案 1 :(得分:2)

我同意Holger的观点,在大多数情况下,仅仅为了使用函数式编程而使用函数编写代码是没有意义的。函数只是一个额外的工具,可以让您以更好的方式编写代码,如集合处理。

然而,您的示例有一个有趣的事情,即您使用String参数a,然后执行一些计算然后返回另一个函数。如果第一个操作需要很长时间,这可能有时有用:

Function<String, Function<Integer,Double>> f = (a) -> {
  if (some-long-computation(a)) return b -> b*1.02;
  if (some-other-long-computation(a)) return b -> return b -> b*1.0;
  else return b -> b;
}

当您使用f参数调用String时,该函数将运行some-long-computationsome-other-long-computation并返回所需的函数:

Function<Integer,Double> fast = f.apply("Some input"); // Slow
Double d1 = fast.apply(123); // Fast!
Double d1 = fast.apply(456); // Fast!

如果f是普通方法,则将其称为f("Some input", 123)两次,然后是 f("Some input", 456)会慢一些,因为您需要运行两次昂贵的计算。当然,这是你可以在没有函数编程的情况下处理的东西,但它是一个返回函数实际上非常适合的地方。