Lambda表达式可以理解为一种匿名函数:没有名称,但有参数列表、函数主体、返回类型。它是行为参数化的一种实现,行为参数化是指将不同的行为作为参数传递给方法,方法的所具备的能力取决于它接收的行为参数。使用Lambda表达式使我们不必为这些行为去编写一堆固定的实现类就能应对不断变化的需求,在1.8之前,可以使用匿名内部类的方式达到相同的效果,只是相对于Lambda表达式来说,匿名内部类的方式会显得啰嗦。

函数式接口

Lambda表达式的使用依赖于函数式接口,只有在接受函数式接口的地方才可以使用Lambda表达式。函数式接口是指只声明了一个抽象方法的接口,可以有多个静态方法、默认方法,如下所示:

@FunctionalInterface
public interface Calculation {
int calculate(int a, int b);
}

@FunctionalInterface注解表示被标注的接口将被设计成一个函数式接口,不是必须的,它主要是在接口违背函数式接口原则时会出现编译错误。比如修改Calculation接口,再添加一个抽象方法就会出现Multiple non-overriding abstract methods found in interface com.cf.demo.lambda.Calculation编译错误:

//编译错误:Multiple non-overriding abstract methods found in interface com.cf.demo.lambda.Calculation
@FunctionalInterface
public interface Calculation {
int calculate(int a, int b); int calculate2(int a, int b);
}

注意:Object类的方法是特例,即使接口声明了多个Object类的方法,也不会被算入“只声明了一个抽象方法”的计数中。如下Calculation接口是正确的函数式接口:

@FunctionalInterface
public interface Calculation {
int calculate(int a, int b); boolean equals(Object obj);
}

Java8提供了一些常用的函数式接口,位于java.util.function包下,并且为了避免装箱操作,还提供了和基本类型对应的接口,我们在实际使用时,可以优先使用这些内置的函数式接口。当然在某些情况我们也需要使用自定义的函数式接口,如需要在Lambda表达式中抛异常时,这种情况就需要自定义一个函数式接口,并声明异常

Lambda表达式语法

Lambda表达式由参数列表箭头(Lambda操作符)Lambda主体三个部分组成。Lambda表达式的参数列表要和函数式接口的参数列表相对应,Lambda主体的返回值也要和函数式接口的返回类型相对应。现在有如下doArithmetic方法,接收两个整型参数以及一个Calculation,doArithmetic方法的行为是由传递的Calculation来决定的,我们可以调用该方法传递不同的Calculation来完成不同的计算:

    public static int doArithmetic(int a, int b, Calculation calculation){
return calculation.calculate(a, b);
}

现在要计算两个数的乘积,用内部类的方式:

	int result = doArithmetic(3, 2, new Calculation() {
@Override
public int calculate(int a, int b) {
return a * b;
}
});
System.out.println(result);//6

用Lambda表达式的方式要更简洁:

	int result = doArithmetic(3, 2, (int a, int b) -> a * b);
System.out.println(result);//6

(int a, int b)是Lambda表达式的参数列表部分,只有一个参数的时候可以省略小括号,这里有多个参数,所以要保留小括号。参数类型可以省略,因为Java编译器能通过上下文推断出数据类型,无需显示的声明:

	int result = doArithmetic(3, 2, (a, b) -> a * b);
System.out.println(result);//6

Lambda主体只有一个语句时,可以省略{}和return,(int a, int b) -> a * b)就是省略之后的写法,我们也可以使用完整的写法:

	int result = doArithmetic(3, 2, (a, b) -> {
return a * b;
});
System.out.println(result);//6

当需要在Lambda表达式中使用‘外部局部变量’时,这个‘外部局部变量’默认是final的,‘外部局部变量’这里是指非Lambda表达式内部定义的局部变量。修改doArithmetic方法,添加一个‘外部局部变量’,为乘积赋个初始值,以下代码是编译不通过的:

	int initialValue = 1;
int result = doArithmetic(3, 2, (a, b) -> a * b + initialValue);
initialValue = 2;//Variable used in lambda expression should be final or effectively final
System.out.println(result);

方法引用

方法引用可以对‘某种特殊情况’下的Lambda表达式进行简化,‘某种特殊情况’是指Lambda表达式要做的事情别的方法实现了,那我们就可以直接使用这个方法,然后像Lambda表达式一样传递即可。方法引用的语法为目标引用放在分隔符::前,方法的名称放在后面,目标引用可以是类名也可以是对象名。通过以下三个例子来介绍方法引用的三种使用方法,新增Arithmetic类,Arithmetic类包含一个静态方法和一个实例方法:

	public class Arithmetic {
public static int multiply(int a, int b){
return a * b;
} public int add(int a, int b){
return a + b;
}
}

1.指向静态方法的方法引用

	int multiplyResult = doArithmetic(3, 2, Arithmetic::multiply);
System.out.println(multiplyResult);//6

2.指向现有对象的实例方法的方法引用

	Arithmetic arithmetic = new Arithmetic();
int addResult = doArithmetic(3, 2, arithmetic::add);
System.out.println(addResult);//5

3.指向任意类型实例方法的方法引用,这种情况有个特点,就是在引用一个对象的方法,而这个对象本身是Lambda的一个参数。比如现在需要实现比较两个数的大小,首先修改calculate方法参数类型为包装类型Integer:

	@FunctionalInterface
public interface Calculation {
int calculate(Integer a, Integer b);
}

比较a和b的大小可以这样写:

	int result = doArithmetic(3, 2, Integer::compareTo);//Integer::compareTo等于a.compareTo(b)
System.out.println(result);//1

构造函数引用

对于一个现有构造函数,可以使用它的名称和new来创建一个它的引用: ClassName::new。再使用构造函数引用时,需要调用的构造器参数列表要和函数式接口的抽象方法的参数要一致。举个例子,现在添加了两个生成String对象的方法:

    public static String generateString(Supplier<String> supplier) {
return supplier.get();
} public static String generateString(String value, Function<String, String> function) {
return function.apply(value);
}

分别使用构造函数引用:

	String result = generateString(String::new);//调用String()构造方法
System.out.println(result); result = generateString("hello Lambda", String::new);//调用String(String original)构造方法
System.out.println(result);

Java8新特性(1):Lambda表达式的更多相关文章

  1. java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合

    java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...

  2. Java8 新特性学习 Lambda表达式 和 Stream 用法案例

    Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...

  3. Java8新特性之Lambda表达式

    lambda表达式是java8给我们带来的几个重量级新特性之一,借用lambda表达式,可以让我们的java程序设计更加简洁.最近新的项目摒弃了1.6的版本,全面基于java8进行开发,本文是java ...

  4. Java8 新特性之Lambda表达式

    1. Lambda 表达式概述 Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递); Lambda 表达式可以写出更简洁,更灵活的代码 ...

  5. 【Java8新特性】Lambda表达式基础语法,都在这儿了!!

    写在前面 前面积极响应读者的需求,写了两篇Java新特性的文章.有小伙伴留言说:感觉Lambda表达式很强大啊!一行代码就能够搞定那么多功能!我想学习下Lambda表达式的语法,可以吗?我的回答是:没 ...

  6. 【Java8新特性】- Lambda表达式

    Java8新特性 - Lambda表达式 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...

  7. 夯实Java基础(二十二)——Java8新特性之Lambda表达式

    1.前言 Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本.因为Java 8里面出现了非常多新的特 ...

  8. java8新特性之——lambda表达式的使用

    lambda表达式简介 个人理解,lambda表达式就是一种新的语法,没有什么新奇的,简化了开发者的编码,其实底层还是一些常规的代码.Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解 ...

  9. 【Java8新特性】Lambda表达式

    一.Lambda 表达式 是什么? Lambda读音:拉姆达. Lambda是一个匿名函数,匿名函数就是一个没有名字的函数. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). ...

  10. Java8 新特性(一)- Lambda 表达式

    2014年3月18日发布了JavaSE 8 不追求技术的新,追求技术的稳定 本质:Lambda 表达式是一个匿名函数 作用:简化代码,增强代码的表达力 Lambda 语法格式 // 格式1:无参无返回 ...

随机推荐

  1. 《JavaScript 模式》读书笔记(5)— 对象创建模式2

    这一篇,我们主要来学习一下私有属性和方法以及模块模式. 三.私有属性和方法 JavaScript并没有特殊的语法来表示私有.保护.或公共属性和方法,在这一点上与Java或其他语言是不同的.JavaSc ...

  2. 使用SlimYOLOv3框架实现实时目标检测

    介绍 人类可以在几毫秒内在我们的视线中挑选出物体.事实上,你现在就环顾四周,你将观察到周围环境并快速检测到存在的物体,并且把目光回到我们这篇文章来.大概需要多长时间? 这就是实时目标检测.如果我们能让 ...

  3. HashMap中使用自定义类作为Key时,为何要重写HashCode和Equals方法

    之前一直不是很理解为什么要重写HashCode和Equals方法,才只能作为键值存储在HashMap中.通过下文,可以一探究竟. 首先,如果我们直接用以下的Person类作为键,存入HashMap中, ...

  4. XDebug的配置和使用

    简介 XDebug是一个开放源代码的PHP程序调试器(即一个Debug工具) 可以用来跟踪,调试和分析PHP程序的运行状况 功能强大的神器,对审计有非常大的帮助. 官网:http://www.xdeb ...

  5. jQuery数组去重复

    例如: var yearArray = new Array("三二一", "三二一", "学历", "学历", &quo ...

  6. js定时器及定时器叠加问题

    回武汉隔离的第二天打卡,武汉加油,逆战必胜!今天想和大家简单聊一下js定时器的问题. 1.setTimeout 延时器 在指定时间后执行一次,注意只会执行一次 当然有的时候我们想用延时器做出定时器的效 ...

  7. 1030 Travel Plan (30分)(dijkstra 具有多种决定因素)

    A traveler's map gives the distances between cities along the highways, together with the cost of ea ...

  8. 1025 PAT Ranking (25 分)

    Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Zhe ...

  9. java接口自动化(三) - 手工接口测试到自动化框架设计之鸟枪换炮

    1.简介 上一篇宏哥介绍完了接口用例设计,那么这一章节,宏哥就趁热打铁介绍一下,接口测试工具.然后小伙伴们或者童鞋们就可以用接口测试工具按照设计好的测试用例开始执行用例进行接口手动测试了.关于手动测试 ...

  10. mpvue微信小程序http请求终极解决方案-fly.js

    fly.js是什么? 一个支持所有JavaScript运行环境的基于Promise的.支持请求转发.强大的http请求库.可以让您在多个端上尽可能大限度的实现代码复用(官网解释) fly.js有什么特 ...