1.Lambda表达式:简洁地表示可传递的匿名函数的一种方式。没有名称,但是有参数列表,函数主体,返回类型,可能还有一个可以抛出的异常列表。
基础语法
()->
()->{***;}
例子:
()->{}
()->"abc"
()->{return "MMM";}
(String s)->s.length()
(Apple a)->a.getWeight() >100
(int x,int y)->{System.out.println(inventory);}
()->44
方法的引用::
(Apple a1,Apple a2)->a1.getWeight(),compareTo(a2.getWeight())
(Apple a)->a.getWeight() 等效于 Apple::getWeight
(str,i)->str.substring(i) 等效于String::substring
(String s)->System.out.println(s) 等效于System.out::println
1.1 List中sort,重写Comparator排序
List<Apple> inventory =
Arrays.asList(new Apple(80, "green"), new Apple(155, "green"), new Apple(120, "red"));
inventory.sort((Apple a, Apple b) -> b.getWeight().compareTo(a.getWeight()));
inventory.sort(Comparator.comparing((Apple a) -> a.getWeight()));//按照重量升序 方法的引用inventory.sort(Comparator.comparing((Apple a) -> a.getWeight()).reversed());//降序
System.out.println(inventory);
可以在函数式接口上使用Lambda表达式
函数式接口就是只定义一个抽象方法的接口
java8中提供很多函数式接口,可以直接使用
Predicate<T> 接口定义了一个test的抽象方法,接受泛型T返回Boolean
Consumer 定义了一个accept抽象方法,接受泛型T 无返回
Function<T,R> 定义了一个apply接口 接受泛型T对象 返回R对象
Supplier<T> ()->T 传入一个泛型T的,get方法,返回一个泛型T 类似于工厂创建对象
针对专门的输入参数类型的函数式接口的名称都要加上对应的原始类型前缀。(好像隐式转换)
DoublePredicate,IntConsumer
(List<String> list)->list.isEmpty() 利用了Predicate<List<String>>
()->new Apple(10) 利用了Supplier<Apple>
(Apple a) -> System.out.println(a.getWeight()) 利用了Consumer(Apple)
(String s)-> s.length() 利用了 Function(String,Integer)或ToIntFunction<String>
任何函数式接口都不允许抛出受检查异常(checked exception)。如果需要Lambda表达式来抛异常,有两种办法
定义一个自己的函数式接口,并声明受检异常,或者把Lambda包在一个try/catch 块中
2.Stream:
List<String> carname = car.stream().filter(a->a.getCarSize()<100).sorted(comparing(Car::getCarLength)).map(Car::getName).collect(Collectors.toList());
List<String> carname = car.parallelStream().filter(a->a.getCarSize()<100).sorted(comparing(Car::getCarLength)).map(Car::getName).collect(Collectors.toList());//并行
filter 返回boolean的函数
filter(Dish::isSmart)
distinct 去重复 distinct()
limit(3) 截取 返回前3个元素
skip(3) 去掉前三个返回剩下的
map(Car::getName) 接受一个函数做为参数,这个函数会被应用到每个元素上,并将其映射成一个新的元素。
返回所有车的名字,可以连续调用map。map(Car::getName).map(String::length) 返回车名字的长度。
对于分隔单词 word.split("") 返回的是数组,一个单词一个数组
words.stream().map(w->w.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());
sorted(comparing(Car::getName)) 按照名称排序
forEach(System.out::println);//打印每个值
短路流 找到就结束不用遍历所有
anyMatch 是否至少匹配一个元素
cars.stream().anyMatch(Car::isBig) 汽车列表里是否有大型车
allMatch 是否匹配所有元素
noneMatch 是否没有任何元素与给定的谓词匹配
findAny 查找元素 返回当前流中的任意元素。与其他流配合使用,只要找到就结束
findFirst() 找到第一个元素
归约 reduce 可以将流中元素组合起来。例如 求和
int product = number.stream().reduce(0,(a,b)->a+b);
int product = number.stream().reduce(0,Integer::sum);//Integer::max Integer::min 最大值 最小值
Optional<Integer> sum = sumbers.stream().reduce((a,b)->(a+b)); //无初始值,返回Optional对象
int product = number.stream().reduce(1,(a,b)->a*b); //所有数相乘 初始值为1,若为0则结果都为0.
long count = cars.stream().count();//计算元素个数
int 重量 = menu.stream().mapToInt(Fish::getWeight).sum();//列表中鱼的重量求和 利用mapToInt的sum方法
两种求和返回值类型不同
Optional<Integer> num = list.stream().map(Student::getAge).reduce(Integer::sum);
System.out.println(num); // Optional[80]
int sum = list.stream().mapToInt(Student::getAge).sum();
System.out.println(sum); // 80
汇总
Colletors类专门为汇总提供了一个工厂方法:Collectors.summingInt。它可以接受一个把对象映射为求和所需int的函数
并返回一个收集器。该收集器在传递给普通的collect方法后即执行我们需要的汇总操作。
int totalAge = list.stream().collect(Collectors.summingInt(Student::getAge));//求和
int totalAges = list.stream().collect(Collectors.reducing(0,Student::getAge,Integer::sum));//求和
Double avgAge = list.stream().collect(Collectors.averagingInt(Student::getAge));//平均数
//总和 平均值 最大 最小 收集器
IntSummaryStatistics studentmenu = list.stream().collect(Collectors.summarizingInt(Student::getAge));
System.out.println(studentmenu);//IntSummaryStatistics{count=5, sum=80, min=12, average=16.000000, max=22}
String allName = list.stream().map(Student::getName).collect(Collectors.joining());//连接字符串
分组
Map<String,List<Student>> map =list.stream().collect(Collectors.groupingBy(Student::getName));
结果:{st2=[com.sy.Student@6576fe71], st1=[com.sy.Student@76fb509a, com.sy.Student@300ffa5d], st3=[com.sy.Student@1f17ae12, com.sy.Student@4d405ef7]}
还可以多级分组名字分组后再用年龄分组
Map<String, Map<String, List<Student>>> mapstudent =
list.stream()
.collect(
Collectors.groupingBy(
Student::getName,
Collectors.groupingBy(
d -> {
if (d.getAge() < 13) return "123";
else return "456";
})));
结果:{st2={456=[com.sy.Student@6576fe71]}, st1={123=[com.sy.Student@76fb509a], 456=[com.sy.Student@300ffa5d]}, st3={456=[com.sy.Student@1f17ae12, com.sy.Student@4d405ef7]}}
还可以在子集里收集数据 列如取子集里最大值maxBy
分区,按照Boolean分区,若对象中有一个boolean属性,可以按照该属性分区 。partitioningBy()
收集器
Collectors类的静态工厂方法
toList 收集到一个List里
toSet 收集到一个set,删除重复项
toCollection 收集到一个Collection<对象>
counting() 计算流中个数 long