JDK 1.8中引入了函数式编程(functional programming,FP),如果您已习惯OOP,一定会感到困惑:什么是函数式编程?这样的编程模式有什么好处?

本文将通过简单的实例令读者对函数式编程有一个大体的了解。

我们知道OOP是以类为基础的,程序中必须首先抽象和定义class。那么FP创建的基础是什么?或者说在Java 8中,至少需要了解什么知识点才能实现基本的函数式编程呢?

本文将首先介绍在Java 8中使用FP所需的基本知识点:Lambda表达式

数据流

基本实例Map> phoneNumbers = new HashMap>();phoneNumbers.put("Zhang Jin", Arrays.asList("3232312323", "8933555472"));phoneNumbers.put("Li Ming", Arrays.asList("12323344", "492648333"));phoneNumbers.put("Li Guoping", Arrays.asList("77323344", "938448333"));Map> filteredNumbers = phoneNumbers.entrySet().stream().filter(x -> x.getKey().contains("Li")).collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));filteredNumbers.forEach((key, value) -> {System.out.println("Name: " + key + ": ");value.forEach(System.out::println);});

上半部分的代码创建了一个从人名到此人所有电话号码的Map,比较简单,但接下来的部分对刚接触Java 8的读者不是一眼就能理解,我们一会儿来详细解释一下。

数据状态不变原则

在分析上面的code前,先来看看FP与我们所熟知的OOP的最大不同。

在面向对象编程时,我们定义类和对象,并使用方法或表达式来执行命令。这些方命令通常会改变程序的数据状态:Integer x = 0;x++;

比如上面的代码,当执行x++后,x的值产生了变化,旧数据被新数据所取代。

相反,在函数式编程中,尽管我们也需要通过方法来执行命令,但命令本身并不会改变程序已有的数据。简单地说就是函数调用对外界不产生副作用,并总是输出新的变量作为调用结果,比如下面的javascript:function max(a, b) {return a > b ? a : b;}var x = 10;var y = 5;var maximum = max(x, y);

此处max并不改变和依赖于外部的x和y,同时每次返回的结果都是一个全新的变量。

代码分析

现在我们回到之前的代码:// create a map, filter it by key valuesMap > filteredNumbers = phoneNumbers.entrySet().stream().filter(x -> x.getKey().contains("Li")).collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));

这段代码首先调用entrySet()来获得phoneNumbers的entries集合,其中每个entry都由一个键值对组成。

接着,在得到的集合上调用stream()方法,该方法会创建一个数据流 (java.util.stream.Stream)。数据流(stream)是Java 8引入的新概念,参考Javadoc,可以将它理解为是一种可以在其上执行顺序或并行聚合操作的数据序列。这些操作可以包括过滤,修改,不同类型的转换等。

得到stream后,代码调用了filter(),filter通过给定的条件来过滤数据。此处的过滤条件是:x -> x.getKey().contains("Li")

该处采用了Java 8引入的lambda表达式,我们可以把lambda表达式看成一个简洁的匿名函数,->左边的x是输入参数,->右边是需要执行的命令。这里的lambda表达式又被称作predicate,它是一个返回boolean类型的函数,stream中的每个element都会被代入该predicate,通过运算出的结果来决定是否在filter()重新返回的stream中被留下或移除。

下一个方法是collect(),可以看到,这里的方法调用都是链式的,原因在于这些方法都归属于Stream接口,所以使用起来非常方便简洁。

collect()方法的用途很简单,它先从stream内获得数据(这里是java.util.Map.Entry),再将数据转变成通常的java collection,比如List, Map, Set等数据结构。这样就重新将stream转变成了我们所熟悉的类型。

Collection的遍历

来看最后一部分代码:filteredNumbers.forEach((key, value) -> {System.out.println("Name: " + key + ": ");value.stream().forEach(System.out::println);});

该代码打印出所有的结果,但并没有使用循环,而是用了Java 8引入的forEach方法。

有了前面的基础,可以很容易看懂:forEach接收一个lambda表达式,filteredNumbers的每个element都讲执行该表达式。由于filteredNumbers是一个map,所以这里lambda表达式参数变成了key, value pair:// expression takes two parameters(key, value) - > {// print person’s nameSystem.out.println("Name: " + key + ": ");// iterate over the person’s phone numbers and print each of themvalue.forEach(System.out::println);}

由于value本身是一个List,所以又在其上调用了forEach。

至此代码的输出为:Name: Li Ming:12323344492648333Name: Li Guoping:77323344938448333

学到的知识点 (以及问题)

本文表述的几个关键点:Java 8通过数据流和lambda表达式使函数式编程成为可能。

Lambda表达式和匿名函数十分相似。

Stream是一种可以在其上执行顺序或并行聚合操作的数据序列,这些操作会作用于序列里的每个元素。

函数式编程模式中的操作倾向于不依赖和不改变已有的数据状态。

数据流操作很简洁性 — 如果不考虑执行效率的话。

但现在您可能会想:函数式编程写出来的东西理解起来似乎更困难 — 我还是喜欢原来的写法, 尽管它要啰嗦很多。

streams操作的执行效率高吗?

如果不改变数据状态,程序应该怎么写才好呢?

这些问题我会在后续的章节中进一步讨论,尽情期待。

本文出自 “Bug之家” 博客,转载请与作者联系!

java里函数式表达式_Java8函数式编程 (一) 数据流和lambda表达式相关推荐

  1. 0202年了,还没有用上Java函数式编程!!!——Lambda表达式

    0202年了,还没有用上Java函数式编程!!!--Lambda表达式 函数式编程是什么 命令式编程(Imperative) 声明式编程(Declarative) 函数式编程(Functional) ...

  2. 提高Java表达能力!不落伍一起掌握Java8中Lambda表达式、函数式接口及方法构造器数组引用

    文章目录 函数式接口概述 函数式接口示例 内置函数式接口 Lambda简述 Lambda语法 方法引用 构造器引用 数组引用 函数式接口概述 只包含一个抽象方法的接口,称为函数式接口. 可以通过 La ...

  3. Java-函数式编程(二)Lambda表达式

    本文首发: Java-函数式编程(二)Lambda表达式 "Lambda 表达式"(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直 ...

  4. Lambda表达式到底是什么?——简单了解Lambda表达式

    一.Lambda表达式是什么 简单来说,Lambda表达式是一个可传递的代码段.可以不借助对象传递的一个代码段.那java作为一个面向对象的语言,为什么要加入这么一个特性呢? 二.为什么使用Lambd ...

  5. 《core JAVA for the impatient》阅读笔记(2) lambda表达式

    lambda表达式 只有一个抽象方法的接口对象,就可以提供一个lambda表达式(函数式接口) 将lambda表达式放入类型为函数式接口的变量中,这样它就被转换为该接口的实例 list.removeI ...

  6. 面试官系统精讲Java源码及大厂真题 - 42 常用的 Lambda 表达式使用场景解析和应用

    42 常用的 Lambda 表达式使用场景解析和应用 引导语 我们日常工作中,Lambda 使用比较多的场景,就是 List 或 Map 下的 Lambda 流操作,往往几行代码可以帮助我们实现多层 ...

  7. lambda表达式方法泛型_模板方法模式–使用Lambda表达式,默认方法

    lambda表达式方法泛型 模板方法模式是Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides在著名的< 设计模式>一书中解释的23种 ...

  8. lambda表达式python菜鸟教程_[c#菜鸟]lambda表达式

    what 一.定义 Lambda 表达式是一种可用于创建 委托 或 表达式目录树 类型的 匿名函数 .通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数.(微软) 理 ...

  9. java 错误代码 返回格式_java – 不兼容的类型:lambda表达式中的错误返回类型?...

    给出以下代码: /** * Prints the grid with hint numbers. */ private void printGridHints() { minesweeperGrid. ...

最新文章

  1. 2.11 向量化-深度学习-Stanford吴恩达教授
  2. Coding:就地合并两个排序数组
  3. http请求post,返回excel文件,并接收
  4. 神经网络优化(二) - 滑动平均
  5. matlab绘3d图
  6. VS2010不能编译.Net3.5项目的解决方法
  7. [转]STL(容器)与DEBUGNEW运算符冲突的解决
  8. 进程间通信——系统调用setjmp()与longjmp()
  9. 计算机话筒技术指标,麦克风
  10. [小知识] WPS恢复本地历史数据
  11. 思科认证华为认证的区别
  12. 源码看JAVA【五】Byte
  13. 每日经典算法题(十六) 九九乘法表
  14. MATLAB画心形立体图
  15. 我在南邮的三年—研二生活
  16. Android应会的网络基本知识
  17. IBM V7000存储升级微码
  18. Android RxJava应用:优雅实现网络请求轮询(无条件)
  19. iOS启动速度优化实践分享
  20. 论文外文文献查找、翻译

热门文章

  1. 基于双TMS320C6678+双XC6VSX315T的6U VPX高速数据处理平台
  2. Query String Object 2.1.7
  3. matlab imwrite函数保存jpg格式图像丢失数据或改变图像
  4. Ubuntu上snmp安装、配置、启动及远程测试完整过程
  5. Ice笔记-利用Ice::Application类简化Ice应用
  6. malloc/free和new/delete的区别
  7. Dagger简单Demo
  8. 重定向index.php,使用htaccess将all重定向到index.php
  9. python颜色的字母代码,如何在python中更改特定印刷字母的颜色?
  10. IMX6的相关音频结构体的定义