Lambda表达式
原创2020年8月31日大约 3 分钟约 1013 字
Lambda式Java8中一个重要的功能,它可以很简洁地表示一个行为或传递代码,现在我们可以把Lambda表达式看作匿名功能,它基本上就是没有声明名称的方法,但和匿名类一样,它也可以作为参数传递给一个方法。JDK本身也提供了大量的FunctionInterface
来支持这一特性。
如何创建一个接口使用Lambda表达式
创建接口之前,首先我们需要了解Lambda到底是什么,我觉得一位老师说的最为贴切,普通方法的参数是参数值,泛型的参数是参数的类型,Lambda的参数是一段代码,当然这句话只能用来理解(因为运行时没有泛型的概念),下面将用ArrayList.forEach()
来展示为什么说Lambda传递的是一段代码。
// 在没有Lambda之前
for(String s: list) {
System.out.pringln(s);
}
// Lambda之后较为繁琐的写法,从这是不是就能看出来为什么说传递的是代码段了呢
// Consumer是一个接口,而之后的代码段是接口的实现
Consumer<String> consumer = (item) -> {System.out.println(item);};
list.forEach(consumer);
// 当参数列表为一个时,可以省略参数的括号
Consumer<String> consumer = item -> {System.out.println(item);};
// 当代码只有一行时,可以省略花括号
Consumer<String> consumer = item -> System.out.println(item);
// 当参数全部作为代码段的参数且只有一行时,可以省略方法参数,该种方式称之为方法引用
Consumer<String> consumer = System.out::println;
实际上创建一个这样的接口非常简单,下面创建一个来模拟一下forEach的操作。
第一步:声明接口
@FunctionInterface
表示这是一个函数式接口,接口中只能有一个方法(不包含默认和静态方法),使用该接口后将会执行更为严格的校验,不符合要求会直接编译报错,Runnable
,Compable
等均是FunctionInterface
。
// 声明一个接口
@FunctionInterface
public interface MyInterface{
void execute(String);
}
第二步:在自己的集合类中创建forEach方法(实验效果忽略泛型)
void forEach(MyInterface interface){
//array为list中维护的数组
for(String s:array){
interface.execute(s);
}
}
第三步:方法调用
MyInterface interface = (item) -> {System.out.println(item);};
MyList.forEach(interface);
这样实际上就完成了一个接口的创建和lambda方式的调用,但是MyInterface
实际上不需要我们手动创建,JDK中已经提供了几个最为常见的基础接口,在集合的stream操作中几乎处处可见他们的影子
// java.util.function.Function下的apply方法,一般用来根据原值返回一个新值
R apply(T t);
// java.util.function.Consumer下的accept方法,与apply方法类似,只是无返回值
// 我们所创建的MyInterface就可以用这个代替了,ArrayList的forEach方法就是用的Consumer接口
void accept();
// java.util.function.Predicate下的test方法,一般用来做逻辑判断并返回boolean
boolean test();
// java.util.function.Supplier下的get方法,一般按照lambda中的方法返回一个新值
T get();
常见的Stream操作
filter
注意返回true表示元素满足条件,false则表示剔除
// 筛选出年龄为18的
list.stream().filter(item -> 18 == item.getAge).collect(toList());
distinct
distinct()
是按照equals()
方法去重的
list.stream().distinct().collect(toList());
limit & skip
limit()
表示获取前N个元素,skip()
表示跳过前N个元素
// 获取前5个元素
list.stream().limit(5).collect(toList());
// 剔除前5个元素
list.stream().skip(5).collect(toList());
map
map()
表示对元素的转换,可以将原先的元素转换成另一种形式
// 将学生的年龄去重之后组成新的List
list.stream()
.map(Student::getAge)
.distinct()
.collect(toList());
groupingBy
按照给定的逻辑分组
// 按照年龄分组,key为年龄,value为该年龄段的学生
Map<Integer,List<Student>> map = list.stream()
.collect(Collectors.groupingBy(Student::getAge()));
// 按照年龄分组,获取每个年龄的人数
Map<Integer,Long> map = list.stream()
.collect(Collector.groupingBy(Student::getAge,Collector.counting()));