和 Lambda 表达式 Say Hello

如果用一大段枯燥的文字去解释一个我们并不熟悉的概念,我觉得和看天书并无区别。我之所以选择学编程,就是因为没有什么是写段代码不能搞定的。那么废话少说,大家先看看清单一中的代码。

清单一

public class Calculater {public static void main(String[] args) {final int a = 1, b = 2;int result = add(new IIntegerMath() {@Overridepublic int operation() {return a + b;}});System.out.println(result);}public static int add(IIntegerMath iIntegerMath) {return iIntegerMath.operation();}}interface IIntegerMath {int operation();}

看完清单一中的代码,估计有人要说我了,因为这段代码在上一篇博客中已经出现过了。但这又何妨,通过一段简单的代码,我们可以挖掘很多知识。在清单一代码的 main 函数中,我调用了 add 函数,并使用了一个匿名内部类作为 add 函数的参数。匿名内部类被设计的目的之一就是,方便程序员将代码作为数据传递。

现在问题来了,大家有没有觉得这样的代码太过于冗余了。我们明明只需要 a + b 这一条语句,却附加了很多其他的代码(命令式代码)。可能由于大家已经习惯了这样的写法,但 Java8 让我们可以用更加简单的代码实现相同的功能。那么,我们一起来看清单二中用** Java8** 实现地与清单一功能相同的代码。

清单二

public class Calculater {public static void main(String[] args) {int a = 1, b = 2;int result = add(() -> a + b);System.out.println(result);}public static int add(IIntegerMath iIntegerMath) {return iIntegerMath.operation();}}interface IIntegerMath {int operation();}

如果有人认为清单二中的代码看着不爽,那么我建议他可以去泡个澡,然后剪个头发。其实清单二中的代码我已经在上篇博客中展示了,但我并没有解释 () -> a + b 是几个意思。

我现在给大家分析下 () -> a + b ,其实这段代码就是一个 Lambda 表达式,也可以理解为一个函数。-> 将参数和 Lambda 表达式的主体分割开了,-> 的左边是参数所在的位置,() 表示无参数;-> 右边的代码是 Lambda 表达式的主体。

即使我们知道了 add 函数中那段代码是什么意思,我认为有些人对于在 add 函数中直接传入一个 Lambda 表达式还是难以理解。那么现在我用另一种方式重写清单二中 main 函数中的代码,请看清单三。

清单三

public static void main(String[] args) {int a = 1, b = 2;IIntegerMath integerMath = () -> a + b;int result = add(integerMath);System.out.println(result);
}

我相信清单三中的代码对于大家来说都很熟悉。当你无法理解使用 Lambda 表达式作为函数参数的用法,你们就将 Lambda 表达式理解为一个对象的引用,虽然按理来说我们不能这么来理解。

Lambda 表达式的多种形式

不带参数的 Lambda 表达式

清单四

public class LambdaLearn {public static void main(String[] args) {INoArguments noArguments =() -> System.out.println("no argument");}
}interface INoArguments {void printOperation();
}

清单四中展示了一个不带参数的 Lambda 表达式,在 -> 的左边使用空括号 () 代表没有参数

带一个参数的Lambda表达式

清单五

public class LambdaLearn {public static void main(String[] args) {IOneArguments<Integer> oneArguments =(a) -> a > 0;}
}interface IOneArguments<T> {boolean assertOneNum(T argument);
}

清单五展示了一个只带一个参数的 Lambda 表达式,因为只有一个参数,所以参数可以用括号包裹起来,也可以不用。

带多个参数的 Lambda 表达式

清单六

public class LambdaLearn {public static void main(String[] args) {IMultiArguments<Integer> multiArguments =(a, b) -> a + b;}
}interface IMultiArguments<T> {T addOperation(T a, T b);
}

清单六中展示了一个带多个参数的 Lambda 表达式。因为有多个参数,所以需要用括号将多个参数包裹起来。

**注意:**我不能用惯性思维去阅读清单六中 Lambda 表达式。该 Lambda 表达式并不是将两个数字相加,而是创建了一个函数,用来计算两个数字相加的结果。变量 multiIArguments 的类型是 IMultiArguments<Integer>,它不是两个数字相加的和,而是将两个数字相加的那行代码。

主体用被{}包裹的 Lambda 表达式

清单七

public class LambdaLearn {public static void main(String[] args) {INoArguments multiStatement = ()  ->  {System.out.println("this is the first code");System.out.println("this is the second code");};INoArguments oneStatement = ()  ->  {System.out.println("only one code");};}
}interface INoArguments {void printOperation();
}

清单七中展示了,如果 Lambda 表达式的主体有多行代码,那么就需要将多行代码用**中括号 {} **包裹。其实当 Lambda 表达式的主体只有一行代码的时候,大家可以根据自己的习惯决定是否使用中括号。

通过 Lambda 表达式来看 Java8

既成事实地final变量

在我们学 Java 基础的时候,我们就知道匿名内部类只能引用外部的 final 变量。但我们却发现,被 Lambda 表达式引用的外部变量并没有被 final 修饰。如清单八中的代码所示,被 Lambda 表达式引用的外部变量 a 和 b 并诶有被 final 修饰,这是因为 Java8 为我们省去了一些操作,这样代码看上去会更加干净舒服。虽然 a 和 b 没有被显示地被 final 修饰,但它们依然是事实上的 final 变量。你们可以根据自己的喜好,选择性地给被 Lambda 表达式引用的外部变量加上 final 修饰符。

清单八

public static void main(String[] args) {int a = 1, b = 2;IIntegerMath integerMath = () -> a + b;int result = add(integerMath);System.out.println(result);
}

类型推断

不知大家是否有注意,本文中使用的 Lambda 表达式都没有为参数指明类型,这是因为 Java8 引入了比 Java7 更加强大的目标类型推断。如清单九中的代码所示, Lambda 表达式的参数 x 并没有被指明类型,但 javac 会根据变量 atLeast 的类型 Predicate<Integer> 推断出目标类型。在日常的开发中,请大家根据具体情况选择是否给 Lambda 表达式的参数显示地指明类型

清单九

Predicate<Integer> atLeast = x -> x > 5;interface Predicate<Integer> {boolean test(T t);
}

彩蛋

其实我的微信里有关注很多技术公众号,但真正喜欢并经常阅读的却寥寥无几,其中刘欣大神的码农翻身就是我非常喜欢的一个公众号。刘欣大哥是一个有 15 年工作经验的前 IBM 架构师,他是一个热爱编程的资深码农,他用心去写好每一篇博客,他的每篇博客都是一个故事,他用一个个精彩短小的故事解释有点枯燥的技术。下面是他公众号的二维码,请关注他,你们会收获很多。

转载于:https://my.oschina.net/u/2501837/blog/1518313

学习 Java8 函数式编程 (二)相关推荐

  1. java8 函数式编程_您必须学习Java 8的函数式编程吗?

    java8 函数式编程 我最近一直在研究Java 8,并掌握了Manning出版的" Java 8 In Action" . 让我印象深刻的第一件事是Java 8独特的销售主张是函 ...

  2. Java8函数式编程语法入门

    Java8函数式编程语法入门 Java8中函数式编程语法能够精简代码. 使用Consumer作为示例,它是一个函数式接口,包含一个抽象方法accept,这个方法只有输入而无输出. 现在我们要定义一个C ...

  3. java8 函数式编程_Java 8函数式编程:延迟实例化

    java8 函数式编程 单例通常会延迟实例化自己,有时,如果对象足够重,则可以延迟实例化类字段. 通常,在走惰性路线时,getter方法(或accessor )必须具有一段代码,该代码块在返回对象之前 ...

  4. Java基础学习之函数式编程Comsumer接口(JDK8)

    前言 从毕业到现在正好三年,高难度的项目做了不少,但是基础这个东西一段时间不接触就会忘得一干二净.话不多说,开始今天的学习! 1. Consumer接口 接触过"消费者",&quo ...

  5. Scala深入学习之函数式编程

    目录 一.函数式编程 二.高阶函数 三.闭包和柯里化 一.函数式编程 示例代码: package matchDemo.function/*** @author : 蔡政洁* @email :caizh ...

  6. [2017.02.23] Java8 函数式编程

    以前学过Haskell,前几天又复习了其中的部分内容. 函数式编程与命令式编程有着不一样的地方,函数式编程中函数是第一等公民,通过使用少量的几个数据结构如list.map.set,以及在这些数据结构上 ...

  7. java8 函数式编程_如何使用Java 8函数式编程生成字母序列

    java8 函数式编程 我偶然发现了用户" mip"一个有趣的堆栈溢出问题 . 问题是: 我正在寻找一种生成字母序列的方法: A, B, C, ..., Z, AA, AB, AC ...

  8. java8 函数式编程_使用Javaslang进行Java 8中的函数式编程

    java8 函数式编程 我们非常高兴地在jOOQ博客上宣布一个客座帖子,该帖子由HSH Nordbank的高级软件工程师Daniel Dietrich (三人的丈夫和父亲)撰写. 他目前作为项目负责人 ...

  9. Java8函数式编程详解

    Java8 函数式编程详解 Author:Dorae Date:2017年11月1日23:03:26 转载请注明出处 说起Java8,可能很多人都已经知道其最大的改进,就是引入了Lambda表达式与S ...

最新文章

  1. 使用Nagios监控网页
  2. 零基础Java学习之构造器
  3. cisco路由器基本命令配置
  4. Scala中的四种访问权限
  5. UVA1262Password(第K字典序)
  6. 机器学习笔记II: 决策树
  7. 深度剖析JDK动态代理机制
  8. Oracle之表示约束状态的关键字Enable/Disable/Validate/Novalidate
  9. 中国双面柔性印刷电路板(FPC)市场趋势报告、技术动态创新及市场预测
  10. 可交换的四本书的封面
  11. 利用ClustrMaps | GoStats | 51la | Google Analytics统计和分析访问量
  12. 【note】编程范式(编程范型)的含义和种类,多范式编程语言
  13. 第七章 课后习题P206
  14. C#--图表控件(Chart)
  15. 服务器网卡驱动装好后本地连接显示,系统装好后网卡驱动也装好了,可是没有本地连接,怎么弄...
  16. Matlab 齐次线性方程组求解举例
  17. 禅道二次开发(三):二次开发实例
  18. 电影《功夫熊猫1》中的管理知识
  19. (附源码)springboot校园兼职系统 毕业设计 031122
  20. 不带电脑看-吃货联盟集合

热门文章

  1. CSS性能优化的几个技巧
  2. Java兔子生兔子问题
  3. Form表单校验_座机号、电话号码
  4. 爱酱,鹿鸣?!自己怎么做一个虚拟二次元偶像?
  5. GNU 和 UNIX 命令
  6. js复制本地文件(单条和批量)
  7. 北京邮电大学计算机学院马华东,马华东(博导)
  8. Python编写汽车类
  9. 罗德里格旋转公式推导(自制)
  10. 支持在线大数据SQL查询平台开源项目