Lambda表达式初步

介绍

什么是Lambda表达式?

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

为何需要lambda表达式?

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

看如下匿名内部类实例:

  1. import javax.swing.*;
  2. import java.awt.event.ActionEvent;
  3. import java.awt.event.ActionListener;
  4.  
  5. public class SwingTest {
  6. public static void main(String[] args) {
  7. JFrame jFrame = new JFrame("My JFrame");
  8. JButton jButton = new JButton("My Button");
  9. // 匿名内部类
  10. jButton.addActionListener(new ActionListener() {
  11. @Override
  12. public void actionPerformed(ActionEvent e) {
  13. System.out.println("Button Pressed");
  14. }
  15. });
  16. jFrame.add(jButton);
  17. jFrame.pack();
  18. jFrame.setVisible(true);
  19. jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  20. }
  21. }

例 1:

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

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

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

  1. import javax.swing.*;
  2.  
  3. public class SwingTest {
  4. public static void main(String[] args) {
  5. JFrame jFrame = new JFrame("My JFrame");
  6. JButton jButton = new JButton("My Button");
  7. // Lambda 表达式
  8. jButton.addActionListener(event -> System.out.println("jButton Pressed"));
  9. jFrame.add(jButton);
  10. jFrame.pack();
  11. jFrame.setVisible(true);
  12. jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  13. }
  14. }

例 2:

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

基本结构

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

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

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

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

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

  1. prarm1 -> {
  2. // 方法体
  3. }

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

  1. prarm1 -> <方法实现>

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

  1. // 原始写法
  2. jButton.addActionListener((ActionEvent event) -> {
  3. System.out.println("jButton Pressed");
  4. });
  5. // 省略参数类型
  6. jButton.addActionListener((event) -> {
  7. System.out.println("jButton Pressed");
  8. });
  9. // 省略小括号
  10. jButton.addActionListener(event -> {
  11. System.out.println("jButton Pressed");
  12. });
  13. // 省略大括号
  14. jButton.addActionListener(event -> System.out.println("jButton Pressed"));

函数式接口

介绍

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

  1. package java.lang;
  2.  
  3. import java.util.Iterator;
  4. import java.util.Objects;
  5. import java.util.Spliterator;
  6. import java.util.Spliterators;
  7. import java.util.function.Consumer;
  8.  
  9. public interface Iterable<T> {
  10. Iterator<T> iterator();
  11.  
  12. default void forEach(Consumer<? super T> action) {
  13. Objects.requireNonNull(action);
  14. for (T t : this) {
  15. action.accept(t);
  16. }
  17. }
  18.  
  19. default Spliterator<T> spliterator() {
  20. return Spliterators.spliteratorUnknownSize(iterator(), 0);
  21. }
  22. }

java.lang.Iterable

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

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

可以获得如下信息:

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

Lambda表达式的作用

看如下示例:

  1. package zze.java8;
  2.  
  3. @FunctionalInterface
  4. interface MyInterface {
  5. void test();
  6. }
  7.  
  8. public class Test2 {
  9. public void test(MyInterface myInterface) {
  10. System.out.println("Test2.test");
  11. myInterface.test();
  12. }
  13.  
  14. public static void main(String[] args) {
  15. Test2 test2 = new Test2();
  16. test2.test(() ->System.out.println("MyInterface.test"));
  17. /*
  18. * Test2.test
  19. * MyInterface.test
  20. */
  21. }
  22. }

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

  1. Test2 test2 = new Test2();
  2. MyInterface myInterface = () -> System.out.println("MyInterface.test");
  3. test2.test(myInterface);
  4. System.out.println(myInterface.getClass());
  5. System.out.println(myInterface.getClass().getSuperclass());
  6. System.out.println(myInterface.getClass().getInterfaces()[]);
  7. /*
  8. Test2.test
  9. MyInterface.test
  10. class zze.java8.Test2$$Lambda$1/990368553
  11. class java.lang.Object
  12. interface zze.java8.MyInterface
  13. */

总结:

  • 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. Python开发【第十篇】:模块

    模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才 ...

  2. 主席树入门——询问区间第k大pos2104,询问区间<=k的元素个数hdu4417

    poj2104找了个板子..,但是各种IO还可以进行优化 /* 找区间[l,r]第k大的数 */ #include<iostream> #include<cstring> #i ...

  3. 【SQL】 MySql与SqlServer差异比较(MySql踩坑全集)

    本文主要记录将数据库从SqlServer移植到MySql的过程中,发现的各种坑爹问题.以SqlServer为主,记录MySql的差异性. 一.IF语句 首先MySql中的的IF语法不同. IF Con ...

  4. python提取网页表格并保存为csv

    0. 1.参考 W3C HTML 表格 表格标签 表格 描述 <table> 定义表格 <caption> 定义表格标题. <th> 定义表格的表头. <tr ...

  5. sql语法总结

    1.创建表 . 创建时间 default current_imestamp(6) 更新时间 default current_timestamp(6)  on update current_timest ...

  6. 初识Python,简单初学代码

    第一个自己手写的代码~ If 与 Elif #!/usr/bin/env python # - * - coding:uft8 - * - Inp = input ( '请输入你的会员级别' ) if ...

  7. python flask_Sqlalchemy管理数据库

    懒癌复发直接粘贴代码,算是做一个简单备份吧. #coding:utf8 from flask import Flask from flask_sqlalchemy import SQLAlchemy ...

  8. xls 编码 utf-8

    直接用 Excel 打开 UTF-8 编码的 CSV 文件会导致汉字部分出现乱码.原因是 Excel 以 ANSI 格式打开,不会做编码识别. ==打开 UTF-8 编码的 CSV 文件的方法:1) ...

  9. Intellij IDEA导入eclipse项目配置jdk、tomcat到浏览器正常访问

    转发自:博客园---Lindp(大佬写的甚好) 以下是转发的正文 intellij idea中文资料网上比较少,对于eclipse的项目如何导入intellij idea也没有完整的说明,本人在这里整 ...

  10. echarts研究

    1.echarts是什么? 关键字:data visualization,canvas,chart Echarts是基于轻量级的canvas类库,纯javaScript实现,MVC封装,数据驱动,一款 ...