为什么引入Lambda表达式?

  • Lambda 表达式产生函数,而不是类。 在 JVM(Java Virtual Machine,Java 虚拟机)上,一切都是一个类,因此在幕后执行各种操作使 lambda 看起来像函数 —— 但作为程序员,你可以高兴地假装它们“只是函数”。
  • Lambda 语法尽可能少,使用 Lambda 表达式可以使代码变的更加简洁紧凑, 易于编写和使用。
  • Lambda 表达式通常比匿名内部类产生更易读的代码。

如何使用Lambda表达式?

首先我们先了解下Lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

任何 Lambda 表达式的基本语法是:

  1. 参数
  2. 接着 ->,可视为“产出”。
  3. -> 之后的内容都是方法体。
    • [1] 当只用一个参数,可以不需要括号 ()。 然而,这是一个特例。
    • [2] 正常情况使用括号 () 包裹参数。 为了保持一致性,也可以使用括号 () 包裹单个参数,虽然这种情况并不常见。
    • [3] 如果没有参数,则必须使用括号 () 表示空参数列表。
    • [4] 对于多个参数,将参数列表放在括号 () 中。
    • [5] 如果在 Lambda 表达式中确实需要多行,则必须将这些行放在花括号中。 在这种情况下,就需要使用 return。到目前为止,所有 Lambda 表达式方法体都是单行。 该表达式的结果自动成为 lambda 表达式的返回值,在此处使用 return 关键字是非法的。 这是 lambda 表达式简化相应语法的另一种方式。

Lambda 表达式实例

// 1. 不需要参数,返回值为 5
() -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y // 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)

我们在 LambdaExpressions.java 中看到了一个 Lambda 表达式,但还有其他语法变体:

interface Description {
String brief();
} interface Body {
String detailed(String head);
} interface Multi {
String twoArg(String head, Double d);
} public class LambdaExpressions { static Body bod = h -> h + " No Parens!"; // [1] static Body bod2 = (h) -> h + " More details"; // [2] static Description desc = () -> "Short info"; // [3] static Multi mult = (h, n) -> h + n; // [4] static Description moreLines = () -> { // [5]
System.out.println("moreLines()");
return "from moreLines()";
}; public static void main(String[] args) {
System.out.println(bod.detailed("Oh!"));
System.out.println(bod2.detailed("Hi!"));
System.out.println(desc.brief());
System.out.println(mult.twoArg("Pi! ", 3.14159));
System.out.println(moreLines.brief());
}
}

输出结果:

Oh! No Parens!
Hi! More details
Short info
Pi! 3.14159
moreLines()
from moreLines()

lambda 表达式规约

  1. Lambda 表达式的参数可以通过上下文推断,如果需要显示声明一个参数的类型,则必须为所有的参数声明类型。

    @FunctionalInterface
    public interface IFunctionMod {
    boolean (int n, int d);
    } IFunctionMod function = (n, d) -> (n % d) == 0 // 合理,n 和 d 的类型通过上下文推断
    IFunctionMod function = (int n, int d) -> (n % d) == 0 // 合理,指定 n 和 d 的类型
    IFunctionMod function = (int n, d) -> (n % d) == 0 // 不合理,须显示声明所有参数类型
  2. Lambda 表达式中抛出的异常需要与目标函数式接口的抽象方法抛出的异常类型兼容。

    以下是合理的:

    @FunctionalInterface
    public interface IFunctionMod {
    boolean (int n, int d) throw Exception;
    } IFunctionMod function = (n, d) -> {
    if (d == 0) {
    // IOException是EXception 的子类,通过类型转换,IOException 可转换为 Exception
    throw new IOException("test");
    }
    return n % d == 0;
    };

    如果反一下,就不行:

    @FunctionalInterface
    public interface IFunctionMod {
    boolean (int n, int d) throw IOException;
    } IFunctionMod function = (n, d) -> {
    if (d == 0) {
    // 父类不能通过自动类型转换转为子类,lambda 表达式抛出的异常类型与抽象方法抛出的异常类型不兼容
    throw new Exception("test");
    }
    return n % d == 0;
    };
  3. Lambda 表达式中参数类型需要与目标函数式接口中抽象方法的参数类型兼容。从接口与实现的角度,可以很容易理解抛出异常兼容 和 参数类型兼容 这2点。

变量作用域

lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

  • lambda 表达式中访问外层的局部变量:

    public class LambdaTester {
    public static void main(String args[]) {
    final int num = 1;
    Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
    s.convert(2); // 输出结果为 3
    } public interface Converter<T1, T2> {
    void convert(int i);
    }
    }
  • lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)

    int num = 1;
    Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
    s.convert(2);
    num = 5;
    //报错信息:Local variable num defined in an enclosing scope must be final or effectively
    final
  • lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

    String first = "";
    Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); //编译会出错

总结

  1. Lambda表达式没有命名,用来像传递数据一样传递操作。
  2. 函数接口指的是只有一个抽象方法的接口,被当做是lambda表达式的类型。

Java8新特性探索之Lambda表达式的更多相关文章

  1. Java8新特性之一:Lambda表达式

    Java8是自java5之后最重大的一次更新,它给JAVA语言带来了很多新的特性(包括编译器.类库.工具类.JVM等),其中最重要的升级是它给我们带来了Lambda表达式和Stream API. 1. ...

  2. Java8新特性之forEach+Lambda 表达式遍历Map和List

    这是Java8系列的第二篇,今天来说一下Java8中forEach的简单使用.我们使用对比的方式来看应该会看得更加清楚,更能理解: 一.遍历Map ============Java8之前的方式==== ...

  3. java8新特性1:lambda表达式和函数式接口

    1.lambda的介绍: 1.1.为什么java语言需要引入lambda表达式? java语言诞生于1995年,历史时间已经相对较长了.在其后的各种新型编程语言中,都有着lambda表达式的内容,并且 ...

  4. Java8新特性(1):Lambda表达式

    Lambda表达式可以理解为一种匿名函数:没有名称,但有参数列表.函数主体.返回类型.它是行为参数化的一种实现,行为参数化是指将不同的行为作为参数传递给方法,方法的所具备的能力取决于它接收的行为参数. ...

  5. java8新特性:内存和lambda表达式

    1.内存变化 取消了永久区和方法区,取而代之的是MetaSpace元空间,即直接使用物理内存,即电脑内存8G则直接使用8g内存,而不是分配内存.因为内存改变,所以调整性能对应的调整参数也随之改变. 2 ...

  6. Java8新特性(拉姆达表达式lambda)

    一.函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是只包含一个方法的接口.比如Java标准库中的java.lang.Runn ...

  7. java8 新特性入门 stream/lambda

    Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggregate operation),或者大批量数据操作 (b ...

  8. 乐字节-Java8核心特性实战之Lambda表达式

    大家好,小乐又来给大家分享Java8核心特性了,上一篇文章是<乐字节|Java8核心实战-接口默认方法>,这次就来讲Java8核心特征之Lambda表达式. Java8 引入Lambda表 ...

  9. Java8新特性探索之Stream接口

    一.为什么引入Stream流 流是一系列与特定存储机制无关的元素--实际上,流并没有"存储"之说.使用流,无需迭代集合中的元素,就可以从管道提取和操作元素.这些管道通常被组合在一起 ...

随机推荐

  1. Java Web学习(五)session、cookie、token

    文章更新时间:2020/09/14 一.引言 动态网页兴起后,会话管理变成开发者需要考虑的一个问题,由于HTTP请求是无状态的,为了区分每个用户,此时引入了会话标识(sessionId)的概念,但是存 ...

  2. 获取IP 地址,失败!解决方法

    命令ip addr 获取IP地址失败,见下图: 解决方法,查看ens33网卡的配置: 控制台,路径输入: vi /etc/sysconfig/network-scripts/ifcfg-ens33 然 ...

  3. C 类型限定符

    C 类型限定符 1. Introduction C 语言中的大部分类型都可以用称为限定符(qualifier)的关键字 const. volatile. restrict. _Atomic 加以限定. ...

  4. 点、像素、分辨率、PPI、DPI等

    屏幕尺寸 屏幕尺寸是屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米. pixel 像素,它是组成图片的最小单元,代表红绿蓝等各种颜色. dot 点,它是屏幕发光.cmos感光的最小物理单元,水平 ...

  5. Java 集合 | 红黑树 | 前置知识

    一.前言 0tnv1e.png 为啥要学红黑树吖? 因为笔者最近在赶项目的时候,不忘抽出时间来复习 Java 基础知识,现在准备看集合的源码啦啦.听闻,HashMap 在 jdk 1.8 的时候,底层 ...

  6. Layman 解决MUI 软键盘弹起挤压页面问题

    问题:在使用mui和H5+进行移动端开发的时候,经常会遇见需要用户输入的情况 当input获取焦点弹起软键盘的时候,经常会遇见软键盘挤压页面.软键盘遮挡输入框等一系列问题: 原因:造成这种现象的原因是 ...

  7. Unicode和多字节字符集

    今天自己写的发现一个输出路径程序使用unicode字符集只能输出单个的首字符,问了一下同事,改为使用多字节字符集,问题解决了 于是上网看了他们的区别:  很多没看完,但起码了解到字符集的演变过程, 转 ...

  8. SpringBoot 完整学习笔记免费分享

    从0到进阶,完全系统性的学习笔记 每次我都会反复拿来观看,因为我们总会有遗漏忘记的地方,但是笔记不会. 希望大家能好好利用它,以下是笔记截图! 以上只是其中的一项部分,这份笔记可以说含金量超高,绝对会 ...

  9. docker-命令帮助

    1. 命令参考     http://www.runoob.com/docker/docker-command-manual.html2. docker-命令,可以使用docker --help查看或 ...

  10. IDEA SpringBoot+JPA+MySql+Redis+RabbitMQ 秒杀系统

    先放上github地址:spike-system,可以直接下载完整项目运行测试 SpringBoot+JPA+MySql+Redis+RabbitMQ 秒杀系统 技术栈:SpringBoot, MyS ...