Lambda表达式初步

介绍

什么是Lambda表达式?

在如 Lisp、Python、Ruby 编程语言中,Lambda 是一个用于表示匿名函数或闭包的运算符

为何需要lambda表达式?

  • 在 Java 中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法。
  • 在 JavaScript 中,函数参数是一个函数,返回值是另一个函数的情况是非常常见的;JavaScript 是一门非常典型的函数式语言。

看如下匿名内部类实例:

 import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; public class SwingTest {
public static void main(String[] args) {
JFrame jFrame = new JFrame("My JFrame");
JButton jButton = new JButton("My Button");
// 匿名内部类
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button Pressed");
}
});
jFrame.add(jButton);
jFrame.pack();
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

例 1:

如上代码很简单,通过第 10 行给第 8 行的按钮注册了一个监听器。而我们知道,当事件触发真正起作用的实际上是执行第 12 行的 actionPerformed 方法,为此我们创建了 ActionListener 实例。

而 Lambda 表达式可以让我们只专注于方法的实现,在注册监听器时我们可以忽略具体需要创建哪个类型的实例。其实在 Idea 中本身就已经给我们提示了,如下:

即匿名内部类的写法是可以用 Lambda 表达式替换的,如下:

 import javax.swing.*;

 public class SwingTest {
public static void main(String[] args) {
JFrame jFrame = new JFrame("My JFrame");
JButton jButton = new JButton("My Button");
// Lambda 表达式
jButton.addActionListener(event -> System.out.println("jButton Pressed"));
jFrame.add(jButton);
jFrame.pack();
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

例 2:

在例 2 中通过第 8 行的 Lambda 表达式替换了例 1 中 10-15 行的匿名内部类写法,不仅代码更简洁,而且含义更直观明了。

基本结构

在 Java 8 中 Lambda 表达式最原始的写法如下:

(类型 prarm1,类型 param2,类型 param3, ...) -> {
// 方法体
}

可以将参数类型省略,编译器可自动推断:

(prarm1, param2, param3, ...) -> {
// 方法体
}

如果只有一个参数,还可以省略小括号:

prarm1 -> {
// 方法体
}

如果方法体只有一行代码,那么大括号也可以省略:

prarm1 -> <方法实现>

用例 2 中的 Lambda 为例演变过程如下:

// 原始写法
jButton.addActionListener((ActionEvent event) -> {
System.out.println("jButton Pressed");
});
// 省略参数类型
jButton.addActionListener((event) -> {
System.out.println("jButton Pressed");
});
// 省略小括号
jButton.addActionListener(event -> {
System.out.println("jButton Pressed");
});
// 省略大括号
jButton.addActionListener(event -> System.out.println("jButton Pressed"));

函数式接口

介绍

在 Java 8 中, Iterable 接口中新增了一个默认函数 forEach 让我们可以更方便的遍历它:

 package java.lang;

 import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer; public interface Iterable<T> {
Iterator<T> iterator(); default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
} default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}

java.lang.Iterable

可以看到它接收一个 java.util.function.Consumer 类型参数,查看 JavaDoc:

该类上标注了一个 @FunctionalInterface 注解,并且注释中还说明了这个接口是一个函数式接口。查看该注解的 JavaDoc:

可以获得如下信息:

  • 这是一个信息性注解,用于标注在一个接口上使一个接口成为函数式接口。
  • 从概念上来说,一个函数式接口有且只能有一个抽象方法。
  • 如果在接口中仅定义了一个抽象方法并且它覆盖了 java.lang.Object 类中公开的方法,那么这个接口就不是函数式接口。
  • 函数式接口的实例可以通过 Lambda 表达式、方法引用或构造方法引用来创建。
  • 如果被该注解标注的类型不满足下面两个条件,那么编译器将生成错误信息。
    1. 该类型是一个接口,不可以是注解类型、枚举、类。
    2. 被注解类型必须满足函数式注解的要求。
  • 如果一个接口满足了函数式接口的要求,但它没有标注该注解,编译器也会将它看作是函数式接口。

Lambda表达式的作用

看如下示例:

package zze.java8;

@FunctionalInterface
interface MyInterface {
void test();
} public class Test2 {
public void test(MyInterface myInterface) {
System.out.println("Test2.test");
myInterface.test();
} public static void main(String[] args) {
Test2 test2 = new Test2();
test2.test(() ->System.out.println("MyInterface.test"));
/*
* Test2.test
* MyInterface.test
*/
}
}

可以看到, Test2 的实例方法 test 实际上是接收一个 MyInterface 对象,而 MyInterface 是一个函数式接口,所以我们可以通过传入 Lambda 表达式作为 myInterface 参数,即:此时传入的 Lambda 表达式就是对函数函数式接口 MyInterface 的实现对象。所以上面代码其实也可以修改为如下:

Test2 test2 = new Test2();
MyInterface myInterface = () -> System.out.println("MyInterface.test");
test2.test(myInterface);
System.out.println(myInterface.getClass());
System.out.println(myInterface.getClass().getSuperclass());
System.out.println(myInterface.getClass().getInterfaces()[]);
/*
Test2.test
MyInterface.test
class zze.java8.Test2$$Lambda$1/990368553
class java.lang.Object
interface zze.java8.MyInterface
*/

总结:

  • Lambda 表达式为 Java 添加了缺失的函数式编程特性,使我们能将函数当做一等公民看待。
  • 在将函数作为一等公民的语言中(如 Python、JavaScript),Lambda 表达式的类型是函数。但在 Java 中,Lambda 表达式是一个对象,它们必须依附于一类特别的对象类型——函数式接口(functional interface)。

Java8(1)之Lambda表达式初步与函数式接口的更多相关文章

  1. java8学习之Lambda表达式初步与函数式接口

    对于Java8其实相比之前的的版本增加的内容是相当多的,其中有相当一大块的内容是关于Lambda表达式与Stream API,而这两部分是紧密结合而不能将其拆开来对待的,但是是可以单独使用的,所以从学 ...

  2. java8学习之Lambda表达式继续探讨&Function接口详解

    对于上次[http://www.cnblogs.com/webor2006/p/8186039.html]已经初步引入的Java8中Stream流的概念,其中使用了map的操作,它需要接受一个Func ...

  3. Java8新特性-Lambda表达式是什么?

    目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...

  4. 怒学Java8系列一:Lambda表达式

    PDF文档已上传Github  Github:https://github.com/zwjlpeng/Angrily_Learn_Java_8 第一章 Lambda 1.1 引言 课本上说编程有两种模 ...

  5. 乐字节-Java8新特性-Lambda表达式

    上一篇文章我们了解了Java8新特性-接口默认方法,接下来我们聊一聊Java8新特性之Lambda表达式. Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作 ...

  6. java8新特性——Lambda表达式

    上文中简单介绍了一下java8得一些新特性,与优点,也是为本次学习java8新特性制定一个学习的方向,后面几篇会根据上文中得新特性一一展开学习.本文就从java8新特性中比较重要的Lambda表达式开 ...

  7. JAVA8学习——深入浅出Lambda表达式(学习过程)

    JAVA8学习--深入浅出Lambda表达式(学习过程) lambda表达式: 我们为什么要用lambda表达式 在JAVA中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法. 在 ...

  8. Java8 新特性lambda表达式(一)初始

    本篇参考Richard Warburton的 java8 Lambdas :Functional Programming for the Masses 学习lambda表达式之前,需要知道什么是函数式 ...

  9. Java8学习笔记----Lambda表达式 (转)

    Java8学习笔记----Lambda表达式 天锦 2014-03-24 16:43:30 发表于:ATA之家       本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人 ...

随机推荐

  1. 十.nginx反向代理负载均衡服务实践部署

    期中集群架构-第十章-nginx反向代理负载均衡章节章节====================================================================== 0 ...

  2. YII 自封装的批量修改的mysql操作类

    <?php /** * Created by PhpStorm. * User: yufen * Date: 2018/8/31 * Time: 9:54 */ namespace app\ba ...

  3. df -h hang 问题

    此处仅截取原文中的解决方案,以便快速查找解决方法. 解决方法如下:1. systemctl restart proc-sys-fs-binfmt_misc.automount; 2. 升级到最新 sy ...

  4. 蒙特卡诺近似与PBM

    介绍蒙特卡诺近似的例子代码 #include<fstream> #include<iostream> #include<cstdlib> #include<c ...

  5. 设计模式学习之访问者模式(Visitor,行为型模式)(21)

    参考:https://www.cnblogs.com/edisonchou/p/7247990.html 在患者就医时,医生会根据病情开具处方单,很多医院都会存在以下这个流程:划价人员拿到处方单之后根 ...

  6. 有标号的DAG计数I~IV

    题解: https://www.cnblogs.com/zhoushuyu/p/10077241.html 看到这么一篇,发现挺不错的..

  7. 在.NET开发中的单元测试工具之(1)——NUnit

    NUnit介绍 NUnit是一个专门针对于.NET来写的单元测试框架,它是xUnit体系中的一员,在xUnit体系中还有针对Java的JUnit和针对C++的CPPUnit,在开始的时候NUnit和x ...

  8. cJSON源码分析

    JSON (JavaScript Object Notation) 是一种常见使用的轻量级的数据交换格式,既有利于人工读写,也方便于机器的解析和生成. 关于JSON格式的定义,参看网站[1].在该网站 ...

  9. Codeforces 1045E. Ancient civilizations 构造 计算几何 凸包

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF1045E.html 4K码量构造题,CF血腥残暴! 题解 首先,如果所有点颜色相同,那么直接连个菊花搞定. ...

  10. python经典书籍推荐:Python核心编程

    作者:熊猫烧香 链接:www.pythonheidong.com/blog/article/27/ 来源:python黑洞网 对<Python核心编程>的褒奖 “ The long-awa ...