Java8-Lambda表达式基础知识

Lambda表达式

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递),其可以代替实现接口中的抽象方法时的书写匿名内部类的繁琐代码。

举个栗子:

Java中有个Runnable接口,直接使用该接口,需要重写实现其接口内部中的抽象方法。如下:

1
2
3
4
5
6
7
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("old run");
}
};
run.run();

该代码可以使用lambda表达式简化为:

1
2
Runnable run1 = () -> System.out.println("lambda run");
run1.run();

1. 基础语法

java8中引入了一个新的操作符”->”,该操作符称为箭头操作符或Lambda操作符,该箭头符号将整个Lambda表达式拆分成两部分:

左侧:Lambda表达式的参数列表,即接口中对应抽象方法的参数列表。

右侧:Lambda表达式中所需要执行的功能,即Lambda表达式体。即需要实现的抽象方法的功能体。

1.1. 语法格式一 无参数,无返回值

对应格式为: () -> 方法体… 括号内无参数

例如:() -> Sysout…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
public void test1 (){
//无参数 , 无返回值 对应格式为: () -> 方法体... 括号内无参数
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("old run");
}
};
run.run();
System.out.println("-----------");
Runnable run1 = () -> System.out.println("lambda run");
run1.run();
}
/*result:
old run
-----------
lambda run
*/

1.2. 语法格式二 有一个参数,无返回值

对应语法格式为 (x) -> 无返回值的方法体

例如: (x) -> System.out.println(x)

若有且只有一个参数,左侧的小括号可以省略不写

例如: x -> System.out.println(x)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 有一个参数 , 无返回值
@Test
public void test2(){
List<String> list = new ArrayList<>();
Consumer<String> consumer = (s) -> list.add(s);//将consumer接收到的对象进行具体的功能的消费
consumer.accept("ddd");
consumer.accept("aaa");
consumer.accept("ccc");
list.forEach(System.out::println);
/*
Result:
ddd
aaa
ccc
*/
}

1.3. 语法格式三 有两个或两个以上参数,有返回值

有两个或两个以上参数,有返回值,并且 lambda 体中有多条语句

1
2
3
4
5
6
7
8
9
10
11
12
13
语法为: 
(x,y) -> {
方法体
return 返回值
}

多条语句必须使用大括号包括在内,
有返回值,需要使用return 返回返回值.
Comparator<Integer> com = (x, y) -> {
System.out.println("x为"+x);
System.out.println("y为"+y);
return Integer.compare(x,y);
};

1
2
3
4
5
6
7
8
9
10
11
12
如果lambda体中只有一条语句,
那么大括号{}可以省略,
return关键字也可以省略

例如:
Comparator<Integer> com = (x,y) -> {
return Integer.compare(x,y);
}

就可以简写成:

Comparator<Integer> com = (x,y) -> Integer.compare(x,y);

1
2
3
4
5
6
7
8
 Lambda表达式的参数列表的 数据类型可以省略不写,
因为JVM编译器可以通过上下文推断出数据类型,即'类型推断'.

即:
(Integer x,Integer y) -> Integer.compare(x,y);

简化成:
(x,y) -> Integer.compare(x,y);

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void test3(){
Comparator<Integer> com = (x, y) -> {
System.out.println("x为"+x);
System.out.println("y为"+y);
return Integer.compare(x,y);
};
System.out.println(com.compare(1111,111));
// x为1111
// y为111
// 1
}

利用用Java内置的Comparator接口(比较器)比较两个字符串的长度,可用lambda表达式表示为:

使用Lambda表达式直接进行该接口的核心方法体的重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//使用Lambda表达式直接进行该接口的核心方法体的重写
Comparator<String> com1 = (x,y) -> {
if(x.length() == y.length()){
return 0;
}else{
if(x.length() > y.length()){
return 1;
}else
return -1;

}
};

System.out.println(com1.compare("aa","aaaaa"));// -1

2. 函数式接口

Lambda表达式需要函数式接口的支持

函数式接口定义: 接口中只有一个抽象方法的接口,称为函数式接口。

可以使用注解 @FuncitonalInterface 修饰,其修饰作用为:限定该接口必须为函数式接口,即该接口中有且只有一个抽象方法。否则无法通过编译。即可以检查是否为函数式接口。

2.1. 自定义一个函数式接口:

1
2
3
4
@FunctionalInterface
public interface Operation<T,R> {
public R operation(T t1, T t2);
}
2.1.1 方案一:写具体实现方法再直接使用
1
2
3
4
5
6
7
8
public void op (Long l1, Long l2, Operation<Long,Long> operation){
System.out.println(operation.operation(l1,l2));
}
@Test
public void testMyOperation(){
op(10l,10l,(x,y) -> x*y);//100
op(100l,200l,(x,y)-> x+y);//300
}
2.1.2 方案二: 先使用lambda表示具体实现方法体,再进行接口中的方法调用,传入具体值:
1
2
3
4
5
@Test
public void testMyOperation(){
Operation<Integer,Integer> op = (x,y) -> x*y;
System.out.println(op.operation(10,10)); //100
}

实际使用时,大多数情况下直接使用Java8内置四大函数式接口,并不要进行自己写函数式接口。