简介
Lambda,“语法糖”,是一个匿名函数,我们可以把Lambda表达式理解为是一个可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使java的语言表达能力得到了提升。
为什么使用Lambda表达式
可以以下代码
@Test
public void test4(){
//使用匿名内部类
Comparator<Integer> comparator = new Comparator<>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
System.out.println(comparator.compare(2,3));
System.out.println("----------------------------------------");
//使用Lambda表达式
Comparator<Integer> handler = (x, y) -> Integer.compare(x, y);
System.out.println( handler.compare(2,3));
}
输出
-1
----------------------------------------
-1
从以上代码可以看出不使用Lambda表达式时,代码非常的繁琐,随着回调模式和函数式编程风格的日益流行,我们需要在Java中提供一种尽可能轻量级的将代码封装为数据的方法。匿名内部类并不是一个好的选择,因为:
1. 语法过于冗余
2. 匿名内部类中this和变量名容易使人产生误解
3. 类型载入和实例创建语义不够灵活
java8解决了这些问题
因此你可以使用更少的代码来实现同样的功能。
Lambda表达式的基础语法
概念
在Java8中引入了一个新的操作符“->” 称作箭头操作符或Lambda表达式。
Lambda分为两个部分
- 左侧:Lambda表达式的参数列表
- 右侧:Lambda表达式中所需执行的功能,即Lambda体
语法格式
- 无参数吗,无返回值
()->System.out.println("hello world!");
- 有参数,并且无返回值
(x)->System.out.println(x);
- 若只有一个参数,则小括号可以省略不写
x->System.out.println(x);
- 有两个以上的参数,有返回值,并且Lambda体中有多条语句时
Comparator<Integer> con = (x,y)->{
System.out.println("函数式接口");
return Integer.compare(x,y);
}
- 若Lambda表达式中只有一条语句时
Comparator<Integer> com =(x,y)->Integer.compare(x,y);
- Lambda 表达式的参数列表的参数类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即类型推断
Comparator<Integer> com=(Integer x,Integer y)->Integer.compare(x,y);
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
注意
Lambda表达式需要“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口称为函数式接口,可以使用注解@FunctionalInterface来修饰,可以检查是否是函数式接口
Java8内置的四大核心函数式接口
介绍
函数式接口 | 说明 | 参数类型 | 返回类型 | 内置方法 | 用途 |
---|---|---|---|---|---|
Consumer | 消费型接口 | T | void | void accept(T t) | 对类型T参数操作,无返回结果。 |
Supplier | 供给型接口 | 无 | T | T get() | 返回T类型参数。 |
Function | 函数型接口 | T | R | R apply(T t) | 对于类型T参数操作,返回R类型参数。 |
Predicate | 断言型接口 | T | boolean | boolean test(T t) | 对类型T进行条件筛选操作,返回boolean. |
- Consumer 消费型接口
/**
* Consumer<T> 消费者类型接口 无返回值
*/
@Test
public void consumer(){
consumers("张三", new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s+"去了北京天安门");
}
});
System.out.println("--------Lambda表达式--------");
consumers("李四",n-> System.out.println(n+"去了九寨沟"));
}
void consumers(String Name,Consumer<String> con){
con.accept(Name);
}
------------------输出------------------
张三去了北京天安门
--------Lambda表达式--------
李四去了九寨沟
- Supplier 供给型接口
/**
* Supplier 供给型接口 T get();
*/
@Test
public void supplier(){
List<Integer> list1 = getNumList(5, new Supplier<Integer>() {
@Override
public Integer get() {
return (int) (Math.random() * 10);
}
});
list1.forEach(System.out::println);
System.out.println("--------Lambda表达式--------");
List<Integer> list = getNumList(5,()->(int)(Math.random()*100));
list.forEach(System.out::println);
}
List<Integer> getNumList(int num , Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i=0; i<num; i++){
Integer n = sup.get();
list.add(n);
}
return list;
}
-----------------输出------------------
3
3
0
1
8
--------Lambda表达式--------
21
5
92
69
69
- Function 函数型接口
/**
* Function<T,R> 函数型接口 R apply(T t);
*/
@Test
public void function(){
String s = handle("hjkwegfkGHJKjksagdhfjklgwhejf", new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
});
System.out.println(s);
System.out.println("--------Lambda表达式--------");
String s2 = handle("hdjagshjgquga", s1 -> s1.toUpperCase());
System.out.println(s2);
}
String handle(String str, Function<String,String> f){
return f.apply(str);
}
--------------输出--------------------
HJKWEGFKGHJKJKSAGDHFJKLGWHEJF
--------Lambda表达式--------
HDJAGSHJGQUGA
- Predicate 断言型接口
/**
* Predicate 断言型接口 boolean test(T t)
*/
@Test
public void predicate(){
List<Integer> list = Arrays.asList(10, 9, 20, 31, 21, 42);
//如果数大于18就加入新的集合中
List<Integer> filter = filter(list, new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer > 18;
}
});
filter.forEach(System.out::println);
System.out.println("--------Lambda表达式--------");
List<Integer> f = filter(list, x -> x > 18);
f.forEach(System.out::println);
}
List<Integer> filter(List<Integer> list, Predicate<Integer> p){
List<Integer> list1 = new ArrayList<>();
for (Integer integer : list) {
if(p.test(integer)){
list1.add(integer);
}
}
return list1;
}
-----------------------输出-----------------
20
31
21
42
--------Lambda表达式--------
20
31
21
42
其他延申函数式接口
函数式接口 | 参数类型 | 返回类型 | 内置方法 | 用途 |
---|---|---|---|---|
BiFunction | T,U | R | R apply(T t,U u) | 对类型T,U参数进行操作,返回R类型结果 |
UnaryOperator | T | T | T apply(T t) | 对类型T对象进行一元运算,并返回T类型的结果 |
BinaryOperator | T,T | T | T apply(T t1,T t2) | 对类型T对象进行二元运算,并返回T类型的结果 |
BiConsumer | T,U | void | void accept(T t,U u) | 对类型T,U参数进行操作 |
ToIntFunction /ToLongFunction / ToDoubleFuction | T | int,long,double | int applyAsInt(T value)/ long applyAsLong(T value) /double applyAsDouble(T value) | 分别计算int,long,double值 |
IntFunction /LongFunction / DoubleFuction | int,long,double | R | R apply(int value)/R apply(longvalue) /R apply(double value) | 参数分别是int,long,double类型函数 |
方法引用
若Lambda体中的功能已经有方法提供了实现,可以使用方法引用(可以将方法引用理解为Lambda表达式的另外一种表现形式)
基本的引用
- 对象::实例方法
User u =new User();
u::getName
- 类名::静态方法名
Comparator<Integer> handler = Integer::compare;
- 类名::实例方法名
User::getName
注意
- 方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中的抽象方法的参数列表和返回值保持一致
- 若Lambda的参数列表的第一参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式为ClassName::MethodName
扩展
- 构造器引用
构造器的参数列表需要与函数式接口中的参数列表保持一致
类名::new
User::new
- 数组引用
类型[]::new
Integer[]::new