Lambda表达式详解(java8新特性,函数式编程)
在JDK1.8中引入了一个重要的新特性:Lambda表达式。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑,在学习Lambda表达式前我们先来思考一下为什么会出现它。
1.为什么会出现Lambda表达式
首先我们思考下在java中如何表示一个值?很简单,定义一个变量,然后赋值
那么如何表示一段代码块的执行逻辑呢?也很简单,定义一个函数,函数方法体写上对应的执行逻辑
可如果我想把这个函数赋予某个变量(aBlockOfCode)并当做入参传递呢?
比如说如此:
在Java 8之前,这么做是不合法的。但是Java 8问世之后,利用Lambda特性,就可以做到了,并且Lambda的设计者还很贴心的帮我们简化了这一定义:
可以看到,我们非常优雅的把“一块代码”赋给了一个变量。而“这块代码”,或者说“这个被赋给一个变量的函数”,就是一个Lambda表达式。
而这个变量的类型是什么呢?
Java8中,定义了一种新的接口类型: 函数式接口,一个接口函数需要被实现的接口类型,我们叫它”函数式接口“ ,并且还为这个接口定义了一个专属声明 @FunctionalInterface ,在接口上加上该声明代表该接口内只有一个函数需要被实现
其实我们发现,上述表达式其实通过定义一个借口的实现类,然后实例化也能达到同样的目的,但是代码量上却多了很多。
这也是Lambda表达式的最直观的作用: 使得代码变得异常简洁。
而且Lambda结合Java8的众多新特性:FunctionalInterface Lib, forEach, stream(),method reference等你会看到这一优势会被无限放大!
2.Lambda表达式的基础语法
Lambda 表达式的2种语法格式如下:
- (parameters) -> expression
- (parameters) -> {statements;}
以下是lambda表达式的重要特征:
1.可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
2.可选的参数圆括号:一个参数无需定义圆括号,但0或多个参数需要定义圆括号。
3.可选的大括号: 如果表达式只有一行,那么表达式两边的花括号可以省略 。
4.可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
Lambda 表达式的简单例子
-
1.多参数的情况
(1). lambda表达式的基本格式为(x1,x2)->{表达式…};
(2).在上式中,lambda表达式带有两个参数,此时参数类型可以省略,但两边的括号不能省
(3)…如果表达式只有一行,那么表达式两边的花括号可以省略
//接受2个带参参数,并返回他们的差值 (int x, String y) -> String.valueOf(x) + y // 4. 接收2无参参数,返回他们的和 (x, y) -> x – y
-
2.无参数的情况
参数的括号不能省略, 其他语法同多参数
//创建并启动一个线程
new Thread(()-> System.out.println("hello, i am thread!")).start();
-
3.一个参数的情况
可以省略参数的括号和类型, 其他语法同多参数
// 接收一个参数,可以省略参数的括号和类型
x -> 2 * x
// 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
3.Java8中提供的常用函数式接口
前面我们说了,为了配合Lambda表达式的使用,Java8中定义了一种新的接口类型: 函数式接口,即一个接口函数需要被实现的接口类型,由 @FunctionalInterface 声明。其实Java为了方便我们的使用,还提供了很多常用函数式接口。
利用函数式接口包:java.util.function
常见的有
Function:提供任意一种类型的参数,返回另外一个任意类型返回值。 R apply(T t);
Consumer:提供任意一种类型的参数,返回空值。 void accept(T t);
Supplier:参数为空,得到任意一种类型的返回值。T get();
Predicate:提供任意一种类型的参数,返回boolean返回值。boolean test(T t);
4.方法引用
Java 8 中还新增了一个关键字“ :: ”我们可以通过 " :: " 关键字来访问类的构造方法,对象方法,静态方法。
演示如下:
1.先自定义一个类
class Demo {
//无参构造
Demo() {}
//有参构造
Demo(String something) {
System.out.println(something);
}
//多参构造
Demo(String something,Integer num) {
System.out.println(something+num);
}
//静态方法
static String startsMethod(String s) {
return String.valueOf(s.charAt(0));
}
//
String methodOne(String s) {
return String.valueOf(s.charAt(s.length()-1));
}
void methodTwo() {
System.out.println();
}
}
2.先定义一个函数式接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tEDdjg5i-1606478057603)(Lambda表达式详解,java8新特性.assets/1606463685803.png)]
接口 IConvert, 传参为类型 F,返回类型 T。
接下来让我们演示通过 ::关键字来进行方法访问。
-
访问静态方法
IConvert<String,String> ic1 = Demo::startsMethod; ic1.convert("静态方法访问");
-
访问对象方法
IConvert<String,String> ic2 = new Demo()::methodOne; ic2.convert("对象方法访问");
-
访问构造方法
IConvert<String,Demo> ic3 = Demo::new; ic3.convert("构造方法访问");
我们可以这样认为,将接口IConvert<F,T>当做一个定义好的模板, Demo类中的各个方法当做这个模板的实现,只要Demo中的方法符合 IConvert接口的入参与出参定义,就可以直接将方法赋予模板。
引用于参考:
https://www.zhihu.com/question/20125256/answer/324121308
本文地址:https://blog.csdn.net/weixin_43828467/article/details/110244897
上一篇: [C#]设计模式-简单工厂-创建型模式
下一篇: 栈原理及其代码实现