欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 宝鼎售后问题提交 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: 琴水玉

引子

将行为作为数据通报

奈何在一行代码里同时计较一个列表的和、最大值、最小值、平均值、元素个数、奇偶分组、指数、排序呢?

谜底是思维反转!将行为作为数据通报。 文艺青年的代码如下所示:

public class FunctionUtil {

   public static <T,R> List<R> multiGetResult(List<Function<List<T>, R>> functions, List<T> list) {
     return functions.stream().map(f -> f.apply(list)).collect(Collectors.toList());
   }

   public static void main(String[] args) {
     System.out.println(multiGetResult(
         Arrays.asList(
             list -> list.stream().collect(Collectors.summarizingInt(x->x)),
             list -> list.stream().filter(x -> x < 50).sorted().collect(Collectors.toList()),
             list -> list.stream().collect(Collectors.groupingBy(x->(x%2==0? "even": "odd"))),
             list -> list.stream().sorted().collect(Collectors.toList()),
             list -> list.stream().sorted().map(Math::sqrt).collect(Collectors.toMap(x->x, y->Math.pow(2,y)))),
         Arrays.asList(64,49,25,16,9,4,1,81,36)));
   }
}

呃,有点矫饰小智慧。 不外要是能将行为作为数据自由通报和施加于数据集发生功效,那么其代码表达本领将如庄子之言,尽情潇洒而无所极限。病毒,不就是将行为匿身于数据中的一种表示么?

行为就是数据。

java8函数框架解读">Java8函数框架解读

函数编程的最直接的表示,莫过于将函数作为数据自由通报,团结泛型推导本领,使代码表达本领得到飞一般的晋升。那么,Java8是怎么支持函数编程的呢?主要有三个焦点观念:

  • 函数接口(Function)
  • 流(Stream)
  • 聚合器(Collector)
  • 函数接口

    关于函数接口,需要记着的就是两件事:

  • 函数接口是行为的抽象;
  • 函数接口是数据转换器。
  • 最直接的支持就是 java.util.Function 包。界说了四个最基本的函数接口:

  • Supplier<T>: 数据提供器,可以提供 T 范例工具;无参的结构器,提供了 get 要领;
  • Function<T,R>: 数据转换器,吸收一个 T 范例的工具,返回一个 R范例的工具; 单参数单返回值的行为接口;提供了 apply, compose, andThen, identity 要领;
  • Consumer<T>: 数据消费器, 吸收一个 T范例的工具,无返回值,凡是用于配置T工具的值; 单参数无返回值的行为接口;提供了 accept, andThen 要领;
  • Predicate<T>: 条件测试器,吸收一个 T 范例的工具,返回布尔值,凡是用于通报条件函数; 单参数布尔值的条件性接口。提供了 test (条件测试) , and-or- negate(与或非) 要领。
  • 个中, compose, andThen, and, or, negate 用来组合函数接口而获得更强大的函数接口。

    其它的函数接口都是通过这四个扩展而来。

  • 在参数个数上扩展: 好比吸收双参数的,有 Bi 前缀, 好比 BiConsumer<T,U>, BiFunction<T,U,R> ;
  • 在范例上扩展: 好比吸收原子范例参数的,有 [Int|Double|Long][Function|Consumer|Supplier|Predicate]
  • 非凡常用的变形: 好比 BinaryOperator , 是同范例的双参数 BiFunction<T,T,T> ,二元操纵符 ; UnaryOperator 是 Function<T,T> 一元操纵符。
  • 那么,这些函数接口可以吸收哪些值呢?

  • 类/工具的静态要领引用、实例要领引用。引用标记为双冒号 ::
  • 类的结构器引用,好比 Class::new
  • lambda表达式
  • 在博文“利用函数接口和列举实现设置式编程(Java与Scala实现)”, “简练代码:一次Java函数式编程的重构之旅” 给出了根基的例子。后头尚有更多例子。重在本身操练和实验。

    聚合器

    先说聚合器。每一个流式计较的末端总有一个雷同 collect(Collectors.toList()) 的要领挪用。collect 是 Stream 的要领,而参数则是聚合器Collector。已有的聚合器界说在Collectors 的静态要领里。 那么这个聚合器是怎么实现的呢?

    Reduce

    大部门聚合器都是基于 Reduce 操纵实现的。 Reduce ,名曰推导,含有三个要素: 初始值 init, 二元操纵符 BinaryOperator, 以及一个用于聚合功效的数据源S。

    Reduce 的算法如下:

    STEP1: 初始化功效 R = init ;

    STEP2: 每次从 S 中取出一个值 v,通过二元操纵符施加到 R 和 v ,发生一个新值赋给 R = BinaryOperator(R, v);反复 STEP2, 直到 S 中没有值可取为止。

    好比一个列表求和,Sum([1,2,3]) , 那么界说一个初始值 0 以及一个二元加法操纵 BO = a + b ,通过三步完成 Reduce 操纵:step1: R = 0; step2: v=1, R = 0+v = 1; step2: v=2, R = 1 + v = 3 ; step3: v = 3, R = 3 + v = 6。

    四要素