为什么引入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. Emit动态生成代理类用于监控对象的字段修改

    利用Emit动态生成代理对象监控对象哪些字段被修改,被修改为什么值 被Register的对象要监控的值必须是Virtual虚类型 必须使用CreateInstance创建对象 必须使用DynamicP ...

  2. Object.defineProperty和proxy

    Object.defineProperty问题 Object.defineProperty() 无法监控到数组下标的变化.vue只能通过以下几种方法来监听 pop() shift() unshift( ...

  3. spring bean的init 方法和 destory方法的三种实现方式

    1.通过@Bean(initMethod ="initPerson",destroyMethod ="destroyPerson" ) public class ...

  4. selenium3介绍

    1.  简介 Selenium是用于测试 Web应用程序用户界面 (UI)的常用框架.它是一款用于运行端到端功能测试的超强工具.您可以使用多个编程语言编写测试,并且 Selenium能够在一个或多个浏 ...

  5. osgEarth使用笔记4——加载矢量数据

    目录 1. 概述 2. 详论 2.1. 基本绘制 2.2. 矢量符号化 2.2.1. 可见性 2.2.2. 高度设置 2.2.3. 符号化 2.2.4. 显示标注 2.3. 其他 3. 结果 4. 问 ...

  6. Python导入模块的几种方法

    Python 模块 Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句. 模块让你能够有逻辑地组织你的 Python 代 ...

  7. Jupyter 绘图怎么显示中文

    1. 简单加2行代码即可. import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = [u'SimHei'] plt.rcPa ...

  8. matlab中ischar确定输入是否为字符数组

    来源:https://ww2.mathworks.cn/help/matlab/ref/ischar.html?searchHighlight=ischar&s_tid=doc_srchtit ...

  9. 加快ASP。NET Core WEB API应用程序。第2部分

    下载source from GitHub 使用各种方法来增加ASP.NET Core WEB API应用程序的生产力 介绍 第1部分.创建测试RESTful WEB API应用程序第2部分.增加了AS ...

  10. SpringCould中的Hystrix

    一.简介 源码地址:https://gitee.com/xiaocheng0902/my-cloud.git 1,定义 Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多 ...