第一章 认识 Java8 以及函数式编程
尽管距离 Java8 发布已经过去 7,8 年的时间, 但时至今日仍然有许多公司, 项目停留在 Java7 甚至更早的版本. 即使已经开始使用 Java8 的项目, 大多数程序员也仍然采用 "传统" 的编码方式.
即使是在 Java7 就已经有了处理异常的新方式 --try-with-resources, 但大多数程序员也仍然采用在 finally 语句中关闭相应的资源.
我认为 Java8 和 Java5 的意义同等重要, Java5 的众多新特性使得 Java 正式迈入编程界的统治地位. 同样, Java8 的发布, 也使得这一门 "古老" 的语言具备了更加现代化的特性.
Java8 最为引入瞩目就是支持函数式编程.
如果说面向对象编程是对数据的抽象, 那么函数式编程就是对行为的抽象[1].
- button.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent event) {
- System.out.println("button clicked");
- }
- });
以上示例来自于《Java 8 函数式编程》
这个示例是为了一个按钮增加一个监听, 当点击这个按钮时, 将会触发打印 "button clicked" 行为.
在 Java 支持函数式编程以前, 我们如果需要传递一个行为常用的方式就是传递一个对象, 而匿名内部类正是为了方便将代码作为数据进行传递.
当然, 函数式编程, 并不是在 Java8 中才提出来的新概念,
函数式编程属于编程范式中的一种, 它起源于一个数学问题. 我们并不需要过多的了解函数式编程的历史, 要追究它的历史以及函数式编程, 关于范畴论, 柯里化早就让人立马放弃学习函数式编程了.
对于函数式编程我们所要知道的是, 它能将一个行为传递作为参数进行传递. 至于其他的, 就留给学院派吧.
第二章 Lambda 表达式
在第一章的示例中, 我们看到在以前想要传递一个行为, 我们通常使用的是匿名内部类, 而从 Java8 开始, 引入了一种全新更为简洁的方式来支持函数式编程, 那就是 --Lambda 表达式.
我们把第一章中的示例改为 Lambda 作为本章的开始.
button.addActionListener(event -> System.out.println("button clicked"));
Lambda 表达式语法规则主体分为两个部分, 中间用 "->" 右箭头连接, 左边代表参数, 右边代表函数主体.
2.1 函数式接口
在 Java 中有一个接口中只有一个方法表示某特定方法并反复使用, 例如 Runnable 接口中只有 run 方法就表示执行的线程任务.
Java8 中对于这样的接口有了一个特定的名称 -- 函数式接口. Java8 中即使是支持函数式编程, 也并没有再标新立异另外一种语法表达. 所以只要是只有一个方法的接口, 都可以改写成 Lambda 表达式. 在 Java8 中新增了 java.util.function 用来支持 Java 的函数式编程, 其中的接口均是只包含一个方法.
例如 Predicate 接口中只包含 test 方法, 该函数接口接受一个输入参数, 返回一个布尔值.
函数式接口中的方法可以有参数, 无参数, 有返回值, 无返回值.
() -> System.out.println("hellobug"), 表示无参数.
event -> System.out.println("hellobug"), 表示只有一个参数.
(x, y) -> {System.out.println(x); System.out.println(y);}, 表示两个参数, 可以不必指定参数类型, 为了更清楚地表达意图, 最好还是加上参数类型,(String x, String y) -> {System.out.println(x); System.out.println(y);}.
接下来我们来编写一个带参数且有返回的函数式接口.
- package com.coderbuff.chapter2_lambda.function;
- /**
- * 函数式接口
- * @FunctionalInterface 注解只是为了表明这是一个函数式接口, 函数式接口只能包含一个方法.
- * @author okevin
- * @date 2020/3/14 23:32
- */
- @FunctionalInterface
- public interface FunctionalInterfaceDemo {
- boolean test(Integer x);
- }
- com.coderbuff.chapter2_lambda.function.FunctionalInterfaceDemo
除了 @FunctionalInterface 注解, 其它和一个普通的接口无任何差别.@FunctionalInterface 注解只是为了标注这是一个函数式接口, 如果标注了 @FunctionalInterface 注解, 此时接口中就只能包含一个方法, 因为函数式接口只能包含一个方法.
接着我们在测试类中编写一个方法, 方法的参数就是这个函数式接口, 这代表了我们将传递行为.
- package com.coderbuff.chapter2_lambda.function;
- /**
- * 按匿名类的方式使用一个函数式接口, 传递行为
- * @author okevin
- * @date 2020/3/14 23:42
- */
- public class AnonymousInnerClassTest {
- private void testAnonymousInnerClass(FunctionalInterfaceDemo functionalInterfaceDemo) {
- Integer number = 1;
- boolean result = functionalInterfaceDemo.test(number);
- System.out.println(result);
- }
- }
- com.coderbuff.chapter2_lambda.function.AnonymousInnerClassTest
testAnonymousInnerClass 方法的含义表示将通过 FunctionalInterfaceDemo#test 方法判断传入的参数 1 返回布尔值.
我们应该如何通过 Lambda 表达式来使用这个函数式接口呢?
前面我们说了, 这个参数代表了我们将传递一个行为, 这个行为决定了 1 返回是 true 还是 false, 我们先通过匿名内部类实现这个接口.
- package com.coderbuff.chapter2_lambda.function;
- /**
- * 按匿名类的方式使用一个函数式接口, 传递行为
- * @author okevin
- * @date 2020/3/14 23:42
- */
- public class AnonymousInnerClassTest {
- private void testAnonymousInnerClass(FunctionalInterfaceDemo functionalInterfaceDemo) {
- Integer number = 1;
- boolean result = functionalInterfaceDemo.test(number);
- System.out.println(result);
- }
- public static void main(String[] args) {
- AnonymousInnerClassTest anonymousInnerClassTest = new AnonymousInnerClassTest();
- anonymousInnerClassTest.testAnonymousInnerClass(new FunctionalInterfaceDemo() {
- @Override
- public boolean test(Integer x) {
- if (x> 1) {
- return true;
- }
- return false;
- }
- });
- }
- }
这是在 Java8 之前通过匿名内部类实现行为的传递, 在有了 Lambda 表达式后, 通过上文的 Lambda 表达式语法规则, 这是一个参数 + 一个返回(Lambda 表达式中有返回值时 return 可以省略), 并且有多行代码.
- anonymousInnerClassTest.testAnonymousInnerClass(number -> {
- if (number> 1) {
- return true;
- }
- return false;
- });
关注公众号 (CoderBuff) 回复 "stream" 抢先获取 PDF 完整版.
近期教程:
《ElasticSearch6.x 实战教程》
《Redis5.x 入门教程》
《Java8 编码实战》
这是一个能给程序员加 buff 的公众号 (CoderBuff)
《On Java 8》
来源: https://www.cnblogs.com/yulinfeng/p/12552786.html