Lambda表达式
简介
- Lambda表达式可称为闭包,
- Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
- 使用Lambda表达式可以使代码变的更加简洁紧凑。
语法
(parameters) -> expression
或(parameters) ->{ statements; }
- Java8中引入了一个新的操作符,
"->"
,该操作符称为箭头操作符或者Lambda操作符,箭头操作符将Lambda表达式拆分成两部分; - 左侧: Lambda表达式的参数列表,对应的是接口中抽象方法的参数列表;
- 右侧: Lambda表达式中所需要执行的功能(Lambda体),对应的是对抽象方法的实现;(函数式接口(只能有一个抽象方法))
- Lambda表达式的实质是对接口的实现;
使用及示例
示例
使用匿名内部类:
Comparator<Integer>com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) { //降序排列
return Integer.compare(o2,o1);
}
};
使用Lambda表达式
Comparator<Integer> com = (x, y) -> Integer.compare(y, x);
用法
- (一) 接口中的抽象方法 : 无参数,无返回值;
例如:Runnable接口下的run方法
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
}
// lambda形式
Runnable runnable = () -> System.out.println("hello");
- (二) 接口中的抽象方法 : 一个参数且无返回值; (若只有一个参数,那么小括号可以省略不写)
// lambda形式
Consumer<String> con = (x) -> System.out.println(x);
con.accept("hello");
- (三) 两个参数,有返回值,并且有多条语句: 要用大括号括起来,而且要写上return
Comparator<Integer> comparator = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
Integer[] nums = {4,2,8,1,5};
Arrays.sort(nums,com);
System.out.println(Arrays.toString(nums));
- (四) 两个参数,有返回值,但是只有一条语句: 大括号省略,return省略
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
Integer[] nums = {4,2,8,1,5};
Arrays.sort(nums,com);
System.out.println(Arrays.toString(nums));
- (五) Lambda表达式的参数列表的数据类型 可以省略不写,因为JVM编译器通过上下文推断出数据类型,即"类型推断",
(Integer x,Integer y ) -> Integer.compare(x,y)
可以简写成(x,y) -> Integer.compare(x,y)
;
函数式接口
- 只有一个抽象方法的接口称为函数式接口;
- 可以使用注解
@FunctionlInterface
来标识,可以检查是否为函数式接口;
例如:
@FunctionalInterface
public interface MyFunction {
String getValue(String str);
}
四大内置函数式接口
如果使用Lambda还要自己写一个接口的话太麻烦,所以Java自己提供了一些接口:
Consumer< T >con
消费性接口:void accept(T t)
;Supplier< T >sup
供给型接口 :T get()
;Function< T , R >fun
函数式接口 :R apply (T t)
;Predicate< T >
断言形接口 :boolean test(T t)
;
Consumer< T >con
消费性接口
有参数,没有返回值
@Test
public void test(){
this.happy(1000,(m) -> System.out.println("消费" + m + "元"));
}
private void happy(double money, Consumer<Double> consumer){
consumer.accept(money);
}
Supplier< T >sup
供给型接口
无参数,有返回值
需求:产生指定个数随机数放入集合中
@Test
public void test(){
List<Integer> list = this.getNumList(10,() -> (int)(Math.random() * 100));
// 遍历,lambda消费性写法
list.forEach((num) -> System.out.println(num));
/*for (Integer num : list) {
System.out.println(integer);
}*/
}
private List<Integer> getNumList(int num, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<>(num);
for (int i = 0; i < num; i++) {
Integer n = supplier.get();
list.add(n);
}
return list;
}
Function< T , R >fun
函数式接口
有参数,有返回值
需求:字符串去空格
@Test
public void test3(){
String str = this.strHandler(" xyn ", s -> s.trim());
System.out.println(str);
}
private String strHandler(String str, Function<String, String> function){
return function.apply(str);
}
Predicate< T >
断言形接口
有参数,有返回值(布尔型)
需求:取出长度大于3的字符串放入新集合
@Test
public void test4(){
List<String> list = Arrays.asList("xyn", "zyn", "abcde", "a", "bb");
list = this.filterStr(list, s -> s.length() > 3);
list.forEach(action -> System.out.println(action));
}
private List<String> filterStr(List<String> strList, Predicate<String> predicate){
List<String> list = new ArrayList<>(strList.size());
strList.forEach(action -> {
if(predicate.test(action)){
list.add(action);
}
});
return list;
}
方法引用,构造器引用,数组引用
方法引用
使用前提: Lambda体中调用方法的参数列表和返回值类型,要和函数式接口中抽象方法的参数列表和返回值类型保持一致;
- 语法格式(一) 对象::实例方法名
PrintStream ps = System.out;
Consumer<String> con = x -> ps.println(x);
con.accept("xyn");
// 简写
Consumer<String> con1 = ps::println;
con1.accept("xyn");
// 更加简写
Consumer<String> con2 = System.out::println;
con2.accept("zyn");
实例2
@Test
public void test(){
User user = new User("zyn",20);
Supplier<String> sup = () -> user.getName();
String name = sup.get();
System.out.println(name);
// 简写
Supplier<Integer> sup2 = user::getAge;
Integer age = sup2.get();
System.out.println(age);
}
- 语法格式(二) 类名::静态方法
@Test
public void test(){
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com2 = Integer::compare;
}
- 语法格式(三) 类名::实例方法名
注意: 若Lambda参数列表中的第一个参数是实例方法的第一个调用者,而第二个参数是实例方法的参数时,可以使用ClassName :: method。
@Test
public void test(){
BiPredicate<String, String> biPredicate = (x, y) -> x.equals(y);
System.out.println(biPredicate.test("xyn","xyn"));
BiPredicate<String, String> biPredicate2 = String::equals;
System.out.println(biPredicate2.test("zyn","zyn"));
}
构造器引用
语法:ClassName::new
注意:需要调用构造器的参数列表,要与函数式接口中的抽象方法的参数列表保持一致;
@Test
public void test5(){
Supplier<User> supplier = () -> new User("xyn",20);
// 构造器引用方式(调用无参构造)
Supplier<User> supplier2 = User::new;
BiFunction<String,Integer,User> biFunction = (x, y) -> new User(x,y);
biFunction.apply("zyn",20);
// 构造器引用方式(调用有参构造)
BiFunction<String,Integer,User> biFunction2 = User::new;
biFunction2.apply("zyn",20);
}
数组引用
语法:Type[]::new
@Test
public void test(){
Function<Integer,String[]> function = x -> new String[x];
System.out.println(function.apply(10).length);
// 数组引用方式
Function<Integer,String[]> function2 = String[]::new;
System.out.println(function.apply(10).length);
}
参考:https://blog.csdn.net/zxzxzx0119/article/details/82392396
视频:https://www.bilibili.com/video/av35195879