九、Lambda
初识Lambda
Lambda表达式可以看成是匿名类一点点演变过来
Lambda 其实就是匿名方法,这是一种把方法作为参数进行传递的编程思想。
虽然代码是这么写,但是,Java会在背后,悄悄的,把这些都还原成匿名类方式
引入Lambda表达式,会使得代码更加紧凑,而不是各种接口和匿名类到处飞。
Lambda表达式虽然带来了代码的简洁,但是也有其局限性。
可读性差,与啰嗦的但是清晰的匿名类代码结构比较起来,Lambda表达式一旦变得比较长,就难以理解。
不便于调试,很难在Lambda表达式中增加调试信息,比如日志。
版本支持,Lambda表达式在JDK8版本中才开始支持
Lambda比较适合用在简短的业务代码中,并不适合用在复杂的系统中,会加大维护成本。
无参无返回值
/***
* lambda格式:(形式参数) -> {代码块}
*/
public class Txt {
public static void main(String[] args) {
//无参无返回值,无参留空即可
filter(()->{System.out.println("我是lambda体");
System.out.println("我是代码块中的多个语句");});
}
public static void filter(Checker ch) {
ch.checker();
}
}
interface Checker {
//无参无返回值的抽象方法
public void checker();
}
有参无返回值
/***
* lambda格式:(形式参数) -> {代码块}
*/
public class Txt {
public static void main(String[] args) {
//有参无返回值,如果参数有且仅有一个,那么小括号可以省略
filter((t,h)->{System.out.println("我是lambda体"+t);
System.out.println("我是代码块中的多个语句"+h);});
}
public static void filter(Checker ch) {
ch.checker(3,8);
}
}
interface Checker {
//有参无返回值的抽象方法
public void checker(int i,int j);
}
有参有返回值
/***
* lambda格式:(形式参数) -> {代码块}
*/
public class Txt {
public static void main(String[] args) {
//有参有返回值,如果参数有且仅有一个,那么小括号可以省略
filter((t,h)->{System.out.println("我是lambda体"+t);
System.out.println("我是代码块中的多个语句"+h);
return "我是返回值";});
}
public static void filter(Checker ch) {
System.out.println(ch.checker(3,8));
}
}
interface Checker {
//有参有返回值的抽象方法
public String checker(int i,int j);
}
省略写法
/***
* lambda格式:(形式参数) -> {代码块}
*/
public class Txt {
public static void main(String[] args) {
//有参有返回值,如果代码块的语句只有一条,可以省略大括号和分号,甚至是return
//省略前
filter((t,h)-> {
return t + h;
});
//省略后
filter((t,h)-> t + h);
}
public static void filter(Checker ch) {
System.out.println(ch.checker(3,8));
}
}
interface Checker {
//有参有无返回值的抽象方法
public int checker(int i,int j);
}
Lambda方法引用
引用静态方法
把静态方法,以参数的形式传递给函数式接口的抽象方法。通俗点,把静态方法体赋给函数式接口的方法体
这个静态方法必须和函数式接口中方法的返回值和参数一致
public class Txt {
public static void main(String[] args) {
filter(Txt::method);
}
//静态方法,必须和函数式接口中方法的返回值和参数一致
public static String method() {
System.out.println("我是静态方法的函数体");
return "我是静态方法的返回值";
}
public static void filter(Checker ch) {
System.out.println(ch.checker());
}
}
interface Checker {
public String checker();
}
引用对象方法
与引用静态方法很类似,只是传递方法的时候,需要一个对象的存在
Txt t = new Txt();
filter(t::method);
引用容器中的对象方法
和引用对象方法一样,只是这个对象在容器中
Lambda聚合操作
使用聚合操作遍历数据
import java.util.ArrayList;
import java.util.List;
public class Txt {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张一",35,12000));
list.add(new Person("张二",85,3000));
list.add(new Person("张三",15,5600));
list.add(new Person("张四",71,3400));
list.add(new Person("张五",55,22200));
//这个格式其实是一条语句
list.stream()
.filter(p -> p.age<60 && p.salary>10000)
.forEach(p->System.out.println(p));
}
}
Stream和管道的概念
Stream 和Collection结构化的数据不一样,Stream是一系列的元素,像生产线上的罐头一样,一串串的出来。
管道指的是一系列的聚合操作。
管道又分3个部分
管道源:在这个例子里,源是一个List
中间操作: 每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操 作,并不会真正进行遍历。
结束操作:当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。 结束操作不会返回Stream,但是会返回int、float、String、 Collection或者像forEach,什 么都不返回, 结束操作才进行真正的遍历行为,在遍历的时候,才会去进行中间操作的相关判断
管道源
//把Collection切换成管道源很简单,调用stream()就行了。
list.stream();
//但是数组却没有stream()方法,需要使用
Arrays.stream(array);
//或者
Stream.of(array);
中间操作
对元素进行筛选:
filter 匹配
distinct 去除重复(根据equals判断)
sorted 自然排序
sorted(Comparator) 指定排序
limit 保留
skip 忽略
转换为其他形式的流
mapToDouble 转换为double的流
map 转换为任意类型的流
结束操作
常见结束操作如下:
forEach() 遍历每个元素
toArray() 转换为数组
min(Comparator) 取最小的元素
max(Comparator) 取最大的元素
count() 总数
findFirst() 第一个元素
## 练习
1)练习-聚合操作
首选准备10个Person对象,age和salary都是随机数。分别用传统方式和聚合操作的方式,把salary第三高的人名称打印出来
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Txt {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(new Person("名字"+i,(int)(Math.random()*100),(int)(Math.random()*7000+3000)));
}
List<Person> list1 = new ArrayList<>(list);//复制集合
//使用传统方式,找出薪水第三高的人
list.sort(new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
if(p1.salary>p2.salary) {
return -1;
}else {
return 0;
}
}
});
System.out.println("传统方式:"+list.get(2));
//使用聚合方式,找出薪水第三高的人
Person p = list1.stream()
.sorted((p1,p2)->p1.salary>p2.salary?-1:1)//排序列表
.skip(2)//忽略前两个
.findFirst()//找出第一个
.get();//获取第一个的对象
System.out.println("聚合方式:"+p);
}
}