网站首页 > java教程 正文
上一篇文章(https://www.toutiao.com/i6824085046475883022/),我们理解了函数式编程基本思想、概念和Java对函数式编程的基本使用。
本篇我们来聊聊lambda表达式和函数式编程的关系。
当提到 Java 8 的时候,Lambda 表达式总是第一个提到的新特性。其实是lambda 表达式把函数式编程风格引入到了 Java 平台上,从而极大的提高 Java 开发人员的效率。
一、引入Lambda的时机
我们先来看两段不同的代码但是是相同的效果
1. 没有lambda之前的代码:
public class OldThread {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("Hello World!");
}
}).start();
}
}
使用 java.lang.Runnable 接口的实现创建了一个新的 java.lang.Thread 对象,并调用 Thread 对象的 start 方法来启动它。Runnable 接口是通过一个匿名内部类实现的。
2. 使用lambda之后的代码:
public class LambdaThread {
public static void main(String[] args) {
new Thread(() -> System.out.println("Hello World!")).start();
}
}
我们发现使用lambda只需一行代码就搞定了之前需要一个匿名类需要完成的事情,所以,Lambda 表达式是创建匿名内部类的语法糖。在编译器的帮助下,可以让开发人员用更少的代码来完成工作。
当然lambda还不仅仅如此。
二、Lambda的深入理解
2.1 lambda如何推断匿名类的类型
第一次使用lambda我们很兴奋,但是也会很迷茫,Java不是一种强类型的编程语言吗?Lambda 表达式没有类的类型信息,好像很多类都可以用相同的lambda表达式来写,编译器是如何推断lambda表达式的匿名类类型呢?
一个 Lambda 表达式的类型由编译器根据其上下文环境在编译时刻推断得来。
举例来说,Lambda 表达式 () -> System.out.println("Hello World!")可以出现在任何要求一个函数式接口实例的上下文中,只要该函数式接口的唯一方法不接受任何参数,并且返回值是 void。这可能是 Runnable 接口,也可能是来自第三方库或应用代码的其他函数式接口。由上下文环境所确定的类型称为目标类型。Lambda 表达式在不同的上下文环境中可以有不同的类型。类似 Lambda 表达式这样,类型由目标类型确定的表达式称为多态表达式
因此使用lambda需要注意以下几点:
- Lambda 表达式的语法很灵活,声明方式类似 Java 中的方法,有形式参数列表和主体。
- 参数的类型是可选的。在不指定类型时,由编译器通过上下文环境来推断。
- Lambda 表达式的主体可以返回值或 void。返回值的类型必须与目标类型相匹配。
- 当 Lambda 表达式的主体抛出异常时,异常的类型必须与目标类型的 throws 声明相匹配。
- 出现歧义的情况下,可能有多个类型满足要求,编译器无法独自完成类型推断。这个时候需要对代码进行改写,以帮助编译器完成类型推断。比如:
public class LambdaTargetType {
@FunctionalInterface
interface A {
void a();
}
@FunctionalInterface
interface B {
void b();
}
class UseAB {
void use(A a) {
System.out.println("Use A");
}
void use(B b) {
System.out.println("Use B");
}
}
void targetType() {
UseAB useAB = new UseAB();
A a = () -> System.out.println("Use");
useAB.use(a);
}
}
这里的UseAB类中有多态方式use,需要在lambda表达式中指定返回的函数类型是A
2.2 变量作用域
在 Lambda 表达式的主体中,经常需要引用上下文环境中的变量。Lambda 表达式使用一个简单的策略来变量的作用域。和很多语言中的闭包不同,Lambda 表达式并没有引入新的命名域(scope)。Lambda 表达式中的变量名称与其所在上下文环境在同一个变量域中。Lambda 表达式在执行时,就相当于这些变量会自动被引入到lambda表达式中。
因此,在 Lambda 表达式中的 this 也与包围它的代码中的含义相同。
下面的代码中,Lambda 表达式的主体中引用了来自包围它的上下文环境中的变量 name。
public void run() {
String name = "Alex";
new Thread(() -> System.out.println("Hello, " + name)).start();
}
需要注意的是,可以在 Lambda 表达式中引用的变量必须是声明为 final 或是实际上 final(effectively final)的。实际上 final 的意思是变量虽然没有声明为 final,但是在初始化之后没有被赋值。因此变量的值没有改变。
三、总结
Java 8 引入的 Lambda 表达式和流处理是可以极大提高开发效率的重要特性。每个 Java 开发人员都应该熟练掌握它们的使用。同时也需要对 Lambda 表达式进行了更深入的了解,知其然更需要知其所以然。
猜你喜欢
- 2024-10-07 python函数式编程(python函数经典例程)
- 2024-10-07 JavaScript 的函数式编程与面向对象编程区别在哪?
- 2024-10-07 函数式编程:Python和Java的实现方式有哪些?
- 2024-10-07 函数式编程与命令式编程的区别以及函数式编程不需要锁
- 2024-10-07 前端同学如何函数式编程?(前端函数式编程和响应式编程)
- 2024-10-07 java8精华-函数式编程-Function (五)
- 2024-10-07 Java函数式编程实战:Consumer、Predicate和Supplier的使用指南
- 2024-10-07 java码农福音:函数式编程和lambda表达式
- 2024-10-07 Java 的函数式接口(必懂知识点!)(jdk1.8函数式接口)
- 2024-10-07 Java新特性之-函数式编程(函数式 java)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)