Lambda表达式
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码
(将代码像数据一样进行传递),其可以代替实现接口中的抽象方法
时的书写匿名内部类的繁琐代码。
举个栗子:
Java中有个Runnable接口,直接使用该接口,需要重写实现其接口内部中的抽象方法。如下:
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("old run");
}
};
run.run();
该代码可以使用lambda表达式简化为:
Runnable run1 = () -> System.out.println("lambda run");
run1.run();
1. 基础语法
java8中引入了一个新的操作符 ->
,该操作符称为箭头操作符
或Lambda操作符
,该箭头符号将整个Lambda表达式拆分成两部分:
左侧:Lambda表达式的参数列表
,即接口中对应抽象方法的参数列表
。
右侧:Lambda表达式中所需要执行的功能,即Lambda表达式体
。即需要实现的抽象方法
的功能体
。
1.1. 语法格式一 无参数,无返回值
对应格式为: () -> 方法体… 括号内无参数
例如:() -> Sysout…
@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)
// 有一个参数 , 无返回值
@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体中有多条语句
语法为:
(x,y) -> {
方法体
return 返回值
}
多条语句必须使用大括号包括在内,
有返回值,需要使用return 返回返回值.
Comparator<Integer> com = (x, y) -> {
System.out.println("x为"+x);
System.out.println("y为"+y);
return Integer.compare(x,y);
};
如果lambda体中只有一条语句,
那么大括号{}可以省略,
return关键字也可以省略
例如:
Comparator<Integer> com = (x,y) -> {
return Integer.compare(x,y);
}
就可以简写成:
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
Lambda表达式的参数列表的 数据类型可以省略不写,
因为JVM编译器可以通过上下文推断出数据类型,即'类型推断'.
即:
(Integer x,Integer y) -> Integer.compare(x,y);
简化成:
(x,y) -> Integer.compare(x,y);
@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表达式直接进行该接口的核心方法体的重写
//使用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. 自定义一个函数式接口:
@FunctionalInterface
public interface Operation<T,R> {
public R operation(T t1, T t2);
}
2.1.1 方案一:写具体实现方法再直接使用
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表示具体实现方法体,再进行接口中的方法调用,传入具体值:
@Test
public void testMyOperation(){
Operation<Integer,Integer> op = (x,y) -> x*y;
System.out.println(op.operation(10,10)); //100
}
实际使用时,大多数情况下直接使用
Java8内置四大函数式接口
,并不要进行自己写函数式接口。
3. Java内置的四大核心函数式接口
Consumer<T> 消费型接口 消费对象
void accept(T t);
Supplier<T> 供给型接口 生成对象
T get();
Function<R,T> 函数型接口 指定特定功能
R apply(T t);
Predicate<T> 断言型接口 进行条件判断
boolean test(T t);
3.1. 消费型接口
Consumer<T>
消费型接口
void accept(T t);
// Consumer<T> 消费型接口
@Test
public void testConsumer(){
//此时的(d) 小括号里有参数
//原因是因为 Consumer接口有参数
//void accept(T t);
consume(1000,(d)-> System.out.println(d));
}
public void consume(Integer n , Consumer<Integer> con){
//函数接口接收 消费 形参n
con.accept(n);
}
3.2. 供给型接口
Supplier<T>
供给型接口
T get();
小括号无参数
// Supplier<T> 供给型接口
@Test
public void testSupplier(){
//T get(); 小括号无参数
List<Integer> numList = getNumList(10,() -> (int)(Math.random()*101));
for ( Integer i: numList
) {
System.out.println(i);
}
}
//调用此方法时,第二个参数提供一个数字集合
public List<Integer> getNumList(int n, Supplier<Integer> sup){
List<Integer> numList = new ArrayList<>();
for (int i = 0; i < n; i++){
numList.add(sup.get()); //通过get方法得到数字 存到numList
}
return numList;
}
3.3. 函数型接口
Function<R,T>
函数型接口
指定特定功能
//Function<R,T> 函数型接口 特定功能
@Test
public void testFunction(){
//将字符串转成大写
String str1 = strHandler("ghslkajh", (s) -> s.toUpperCase());
System.out.println(str1);
}
// Function<R,T> 函数型接口
//定义一个处理字符串功能型接口函数
public String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
3.4. 断言型接口
Predicate<T>
条件判断
boolean test(T t);
返回boolean
//断言型接口 Predicate<T>
// boolean test(T t); 返回boolean
@Test
public void testPredicate(){
//返回长度大于3的字符串
List<String> s1 = strFilter(Arrays.asList("huzhiqi", "adaad", "1231", "414441", "gagsgasg"), (s) -> s.length() > 3);
System.out.println(s1); //[huzhiqi, adaad, 1231, 414441, gagsgasg]
//返回包含d的字符串
List<String> s2 = strFilter(Arrays.asList("huzhiqi", "adaad", "1231", "414441", "gagsgasg"), (s) -> s.contains("d"));
System.out.println(s2); // [adaad]
}
//使用断言型接口过滤字符串
public List<String> strFilter(List<String> strs, Predicate<String> pred){
List<String> list = new ArrayList<>();
for (String s:strs
) {
//利用断言型接口进行指定功能判断 即一个功能性条件判断
if(pred.test(s)){
//过滤功能
list.add(s);
}
}
return list;
}