1.简介
Lambda表达式是 jdk1.8 引入的一个新特性,它是函数式编程在Java中的一种体现。也是1.8最值得学习的新特性。
-
Lambda表达式的引入简化了匿名内部类的语法,让代码更加简洁明了。
-
Lambda表达式提供了一种便捷的语法形式,使得函数可以作为参数传递给方法,或者作为返回值返回。
-
Lambda表达式的引入使得Java在并行编程方面具备了更好的支持。
-
lambda表达式本质来讲,是一个匿名函数(匿名方法)。(匿名方法:方法名没有名字)
-
Lambda表达式只能作用于函数式接口(有且只有一个抽象方法的接口)
2.lambda基础语法
(1)语法与解析
语法:
(parameters)-> expression (parameters:参数)
或者 (parameters)-> { statements; } (statements:语句)
解析:
1. -> (箭头)将参数与Lambda主体分隔开来。
参数部分:
1.参数可以是任意合法的Java参数列表,可以为空或包含一个或多个参数。
2.参数列表的类型名可以省略。 不能出现有些省略了,有些没有省略的情况。
3.如果参数列表中,参数的数量有且只有一个,则小括号可以省略。
Lambda主体:
1.Lambda主体可以是一个表达式,表达式外的大括号,可加可不加。 没有大括号时,return关键字必须省略。
2.也可以是一个代码块。将按照常规的Java语法执行,并且您可能需要使用return语句来返回值。
(2).语法案例:
1.无参数的lambda表达式:
()-> System.out.println("Hello ,Lambda!");
2.带有参数的lambda表达式
(int m) -> System.out.println(m); //可以省略类型
或
(m) -> System.out.println(m);
或
m -> System.out.println(m);//只有一个参数,可以省略小括(int x, int y) -> System.out.println(x + y);
或者
(x, y) -> System.out.println(x + y);
3.带有多行代码的lambda表达式:
(x, y) -> {
int sum = x + y;
System.out.println("Sum: " + sum);
return sum;
}
3.Lambda的应用场景
(1)lambda的应用场景
lambda表达式,只能作用于函数式接口。
函数式接口:有且只有一个抽象方法的接口。
(2)案例演示:
创建一些接口:
1.里面的抽象方法 没有形参,也没有返回值
interface NoParameterNoReturn{
void print();
}
2.一个形参,没有返回值
interface OneParameterNoReturn{
void print(String info);
}
3.多个形参,没有返回值
interface MuilParameterNoReturn {
void print(String info,int age);
}
4.没有形参,带返回值
interface NoParameterReturn{
int calculate();
}
5.一个形参,带返回值
interface OneParameterReturn{
int calculate(int a);
}
6.多个形参,带返回值
interface MuilParameterReturn {
int calculate(int a,int b);
}
测试:
1.使用实现类的方式,实现NoParameterNoRetrun接口,打印"java编程真简单"
class Class1 implements NoParameterNoReturn{ //写一个类实现接口,重写接口里的抽象方法
@Override
public void print() {
System.out.println("java编程真简单");
}
}
public static void main(String[] args) {
NoParameterNoReturn class1 = new Class1();
class1.print();//调用类里重写的方法
}
2.使用匿名内部类的方式,实现NoParameterNoRetrun接口,打印"我一定能学会java"
public static void main(String[] args) {
NoParameterNoReturn nono = new NoParameterNoReturn(){ //匿名内部类
public void print() {
System.out.println("我一定能学会java");
}
};
nono.print();//调用匿名内部类的方法
}
3.使用lambda表达式,实现NoParameterNoReturn接口,打印"哈哈哈,我哭了...“
NoParameterNoReturn n1 = ()-> System.out.println("哈哈哈,我哭了...");
n1.print();
4.使用lambda表达式,实现OneParameterNoReturn接口,打印"'我喜欢'+形参",传入'苹果'
OneParameterNoReturn oneNoRetrun = info-> System.out.println("我喜欢"+info);//一个参数小括号可以省略
oneNoRetrun.print("苹果");
5.使用lambda表达式,实现MuilParameterNoReturn接口,打印两个参数拼接的效果,传入"我今年","18"
MuilParameterNoReturn muilNoReturn = (m,n)-> System.out.println(m+n);
muilNoReturn.print("我今年",18);
6.使用lambda表达式,实现NoParameterReturn接口,计算两个随机数,区间[25,40]的和"
NoParameterReturn noR1 = ()->{
int a = (int)(Math.random()*16)+25;
int b = (int)(Math.random()*16)+25;
return a+b;
};
int r1 = noR1.calculate();
System.out.println("r1="+r1);
7.使用lambda表达式,实现OneParameterReturn接口,计算形参的立方,测试传入3
OneParameterReturn oneR2 = x -> x*x*x;
int r2 = oneR2.calculate(3);
System.out.println("r2="+r2);
// OneParameterReturn oneR2 = x-> {
// int a = x*x*x;
// return a;
// };
// int calculate = oneR2.calculate(3);
// System.out.println(calculate);
8.使用lambda表达式,实现MuilParameterReturn接口,计算两个形参的立方和,测试传入3和4
MuilParameterReturn mR1 = (x,y) -> x*x*x+y*y*y;
int r3 = mR1.calculate(3,4);
System.out.println("r3="+r3);
//或者
// MuilParameterReturn mR2 = (x,y)->{
// int n = x*x*x;
// int m = y*y*y;
// int sum = m+n;
// return sum;
// };
// int calculate1 = mR2.calculate(3, 4);
// System.out.println(calculate1);
4.变量的捕获
(1)匿名内部类的变量捕获
在Java中,匿名内部类可以捕获外部变量,即在匿名内部类中引用并访问外部作用域的变量。这种行为称为变量捕获(Variable Capturing)。
在匿名内部类中,可以捕获以下类型的变量:
-
实例变量(Instance Variables):如果匿名内部类位于一个实例方法中,它可以捕获并访问该实例的实例变量。
-
静态变量(Static Variables):匿名内部类可以捕获并访问包含它的类的静态变量。
-
方法参数(Method Parameters):匿名内部类可以捕获并访问包含它的方法的参数。
-
本地变量(Local Variables):匿名内部类可以捕获并访问声明为final的本地变量。从Java 8开始,final关键字可以省略,但该变量实际上必须是最终的(即不可修改)。
案例:匿名内部类在一个实例方法中
定义一个接口:不用一定是函数式接口
interface Mytest1{
void test1();
void test2();
}
测试:
public class VariableCatch {
private int a;//实例变量
private static int b;//静态变量
static {
b=2; //在静态代码块里赋值
}
public VariableCatch(){
a=1;
}
public void m1(int c){
int d =4;
Mytest1 mt = new Mytest1() {
@Override
public void test1() {
//访问外部类的成员变量:外部类名.this.成员变量 或者直接写
System.out.println("instance variable: "+a);
//访问外部类的静态变量:外部类名.静态变量, 或者直接写
System.out.println("static variable: "+b);
//匿名内部类访问的方法形参也只能访问,不能覆盖。
System.out.println("method parameter: "+c);
//匿名内部类访问的局部变量是默认被final修饰的;final修饰的变量只能初始化一次。
System.out.println("native variable: "+d);
}
@Override
public void test2() {
}
};
mt.test1();
}
public static void main(String[] args) {
VariableCatch variableCatch = new VariableCatch();
variableCatch.m1(3);
}
}
捕获成功:
修改变量的值出现的结果:
1.在匿名内部类的方法体中修改变量的值 ,编译出错
2.在定义的方法中修改变量,出现编译错误。
(2) lambda表达式的变量捕获
在Lambda表达式中,同样可以捕获外部作用域的变量。Lambda表达式可以捕获以下类型的变量:
-
实例变量(Instance Variables):Lambda表达式可以捕获并访问包含它的实例的实例变量。
-
静态变量(Static Variables):Lambda表达式可以捕获并访问包含它的类的静态变量。
-
方法参数(Method Parameters):Lambda表达式可以捕获并访问包含它的方法的参数。
-
本地变量(Local Variables):Lambda表达式可以捕获并访问声明为final的本地变量。从Java 8开始,final关键字可以省略,但该变量实际上必须是最终的(即不可修改)
案例:
public class _01InnerClassDemo {
private int a; //实例变量
private static int b;//静态变量
static{
b = 2;
}
public _01InnerClassDemo() {
a = 1;
}
public void m2(int c){
int d = 4;
MyTest mt = () ->{
//访问外部类的成员变量:外部类名.this.成员变量 或者直接写
System.out.println("instance variable: "+a);
//访问外部类的静态变量:外部类名.静态变量, 或者直接写
System.out.println("static variable: "+b);
//访问的方法形参也只能访问,不能覆盖。
System.out.println("method parameter: "+c);
//访问的局部变量是默认被final修饰的;final修饰的变量只能初始化一次。
System.out.println("native variable: "+d);
};
mt.test1();
}
public static void main(String[] args) {
//测试:创建外部类对象
_01InnerClassDemo c1 = new _01InnerClassDemo();
c1.m2(3);
}
}
interface MyTest{
void test1();
}
同上面一样,变量也不可修改。
5.Lambda表达式在集合中的应用
(1)集合的排序,使用比较器的时候
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("abdgc");
list.add("ab");
list.add("abdgcghsuhcd");
list.add("abdsugc");
list.add("abdc");
//按照字符串的长度降序排序
list.sort((l1,l2)->l2.length()-l1.length());
System.out.println(list);
}
(2)forEach迭代元素
1)list迭代
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("abdgc");
list.add("ab");
list.add("abdgcghsuhcd");
list.add("abdsugc");
list.add("abdc");
list.forEach(list1-> System.out.println(list1));
//或者更简单的
list.forEach(System.out::println);
}
2)Set迭代
public static void main(String[] args) {
Integer[] arry = new Integer[]{11,25,4,1,15,6,2,3};
List<Integer> list = Arrays.asList(arry);
//想要Set集合
Set<Integer> set = new HashSet<>(list);
set.forEach(s-> System.out.println(s));
//或者
set.forEach(System.out::println);
}
3)Map迭代
public static void main(String[] args) {
Map<String,Integer> map=new HashMap<>();
map.put("张三",18);
map.put("李四",19);
map.put("王五",17);
map.put("赵六",28);
//key的迭代
map.keySet().forEach( key -> System.out.println(key));
//entrySet的迭代
map.entrySet().forEach(entry-> System.out.println(entry.getKey()+"="+entry.getValue()));
//values的迭代
map.values().forEach(v-> System.out.println(v));
}
(3)根据条件移除元素
public static void main(String[] args) {
List<Integer> list = Arrays.asList(18,19,20,19,24);
List<Integer> nums = new ArrayList<>(list);
System.out.println(nums);//[18, 19, 20, 19, 24]
/**
* removeIf(Predicate filter): 满足过滤条件就会删除
* 源码解析:
* 内部逻辑就是一个迭代器遍历集合,根据条件做删除操作
* 条件就是filter的test方法。
* Predicate 是一个函数式接口,里面有boolean test(T t)方法,因此我们在使用时就是写一个
* lambda表达式来实现test方法即可。
*/
boolean b = nums.removeIf(m -> m.equals(19));
System.out.println(b);
System.out.println(nums);//[18, 20, 24]
}
复习remove方法:
public static void main(String[] args) {
List<String> list = Arrays.asList("18","19","20","19","24");
List<String> nums = new ArrayList<>(list);
System.out.println(nums);//[18, 19, 20, 19, 24]
// nums.remove("19");
// System.out.println(nums);//[18, 20, 19, 24]只能删除一个
List<String> list1 = new ArrayList<>();
list1.add("19");
list1.add("21");
nums.removeAll(list1); //可以全部删除
System.out.println(nums);//[18, 20, 24]
}
6.Lambda表达式的优缺点
(1)优点:
-
简洁性:Lambda表达式提供了一种更简洁、更紧凑的语法,可以减少冗余的代码和样板代码,使代码更易于理解和维护。
-
代码可读性:Lambda表达式使得代码更加自解释和易读,可以直接将逻辑集中在一起,提高代码的可读性和可维护性。
-
便于并行处理:Lambda表达式与Java 8引入的Stream API结合使用,可以方便地进行集合的并行处理,充分发挥多核处理器的优势,提高代码的执行效率。
-
避免匿名内部类的繁琐语法:相比于使用匿名内部类,Lambda表达式的语法更为简洁,减少了冗余的代码,提高了编码效率。
(2)缺点:
-
只能用于函数式接口:Lambda表达式只能用于函数式接口(只有一个抽象方法的接口),这限制了它的使用范围。如果需要使用非函数式接口,仍然需要使用传统的方式,如匿名内部类。
-
可读性的折衷:尽管Lambda表达式可以提高代码的可读性,但在某些复杂的情况下,Lambda表达式可能变得难以理解和阅读,特别是当表达式变得过于复杂时。
-
变量捕获的限制:Lambda表达式对捕获的变量有一些限制。它们只能引用final或实际上的最终变量,这可能对某些情况下的代码编写和调试带来一些困扰。
-
学习曲线:对于习惯于传统Java编程风格的开发者来说,Lambda表达式是一项新的概念,需要一定的学习和适应过程。
7.集合的流式编程
(1)Stream编程的简介
如果想要进行集合的流式编程,必须使用集合实例调用其stream方法
Stream是对集合操作的增强,流不是集合的元素,不是一种数据结构,不负责数据的存储的。流更像是 一个迭代器,可以单向的遍历一个集合中的每一个元素,并且不可循环。
(2)为什么要使用集合的流式编程
有些时候,对集合中的元素进行操作的时候,需要使用到其他操作的结果。在这个过程中,集合的流式 编程可以大幅度的简化代码的数量。将数据源中的数据,读取到一个流中,可以对这个流中的数据进行 操作(删除、过滤、映射...)。每次的操作结果也是一个流对象,可以对这个流再进行其他的操作。
(3)使用流式编程的步骤
1. 传统方式,如果对集合中的元素做处理时,可能要书写大量的代码,比如增加,删除,过滤等
2. 集合的流式编程:是JDK1.8引入的两个重要特性之一。另一个是Lambda表达式
3. 集合的流式编程是对传统方式的一种简化操作
4. 集合的流式编程,分三步:
--第一步:获取数据源(关联数据源),返回Stream对象
--第二步:对Stream对象进行各种处理,处理后的结果依然是Stream对象
--第三步:对Stream对象的最后整合处理。处理后的结果一般情况下不再是Stream对象,可能是一个具体的数字,字符串,或者一个新的集合。
-- 注意:整个过程中,数据源本身并不会发生变化。
1)获取数据源(关联数据源)
将数据源中的数据读取到流中,进行处理。
public static void main(String[] args) {
List<String> list = Arrays.asList("18","19","20","19","24");
// 获取的流对象,是串行的,好比只有一个人去工作
Stream<String> stream = list.stream();
//获取的流对象,是并行的,好比有多个人同时工作。效率高
Stream<String> stringStream = list.parallelStream();
}
2)最终操作
(1)最终操作的简介
将流中的数据整合到一起,可以存入一个集合,也可以直接对流中的数据进行遍历、数据统计... ,通过 最终操作,需要掌握如何从流中提取出来我们想要的信息。
注意事项:最终操作,之所以叫最终操作,是因为,在最终操作执行结束后,会关闭这个流,流中的所有数据都会销毁。如果使用一个已经关闭了的流,会出现异常:stream has already been operated upon or closed
(2)最终操作的方法
1.colllect:搜集方法,可以将流的数据搜集成一个新的集合。
collect方法的参数,是一个Collector接口,而且这个接口并不是一个函数式接口。实现这个接口, 可以自定义收集的规则。但是,绝大部分情况下,不需要自定义,直接使用Collectors工具类提供的方法即可
(1)搜集成List集合
public static void main(String[] args) {
List<String> list = Arrays.asList("18","19","20","19","24");
// 获取的流对象,是串行的,好比只有一个人去工作
Stream<String> stream = list.stream();
//最后操作,会关闭流
List<String> collect = stream.collect(Collectors.toList());
System.out.println(collect);//[18, 19, 20, 19, 24]
}
(2)搜集成Set集合
public static void main(String[] args) {
List<String> list = Arrays.asList("18","19","20","19","24");
// 获取的流对象,是串行的,好比只有一个人去工作
Stream<String> stream = list.stream();
//最后操作,会关闭流,Set集合不允许重复
Set<String> collect = stream.collect(Collectors.toSet());
System.out.println(collect);//[24, 18, 19, 20]
}
(3) 搜集成Map集合
public static void main(String[] args) {
List<Integer> list = Arrays.asList(12,23,5,41,36,20);
Stream<Integer> stream = list.stream();
Map<String, Integer> collect = stream.collect(Collectors.toMap(e -> "" + e, e -> e));
System.out.println(collect);//{23=23, 12=12, 36=36, 5=5, 41=41, 20=20}
}
2.reduce:将流中的数据按照一定的规则聚合起来。(比如计算数据源的元素之和)
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
//计算数据源的元素之和 方法参数也是lambda表达式: 对应的抽象方法 R apply(T t, U u);
//返回的类型:Optional,需要调用它的get方法,获取里面的数据
Optional<Integer> reduce = stream.reduce((a, b) -> (a + b));
Integer integer = reduce.get();
System.out.println(integer);//15
}
对Map的键或值进行归约操作
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("xiao",25);
map.put("xi",20);
map.put("x",30);
Integer reduce = map.values().stream().reduce(0,(a, b) -> a + b);
System.out.println(reduce);//75,value的和
String reduce1 = map.keySet().stream().reduce("", (a, b) -> a + b);
System.out.println(reduce1);//xixiaox key的拼接操作
}
3.count统计流中的元素数量
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
long count = stream.count();
System.out.println(count);//5
}
4.遍历、迭代流中的数据
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
stream.forEach(list1-> System.out.println(list1));
//或者
//stream.forEach(System.out::println);
}
5.max&min获取流中的最大的元素、最小的元素。
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
/**
* max方法:根据规则得到的最后一个元素(即都取最后一个元素)
*/
//升序排序
// Integer max = stream.max((c1, c2) -> c1 - c2).get();
// System.out.println("max:"+max);//5
//降序排序
// Integer max1 = stream.max((c1, c2) -> c2-c1).get();
// System.out.println("max1:"+max1);//1
/**
* min方法:根据规则得到的第一个元素(即都取第一个元素)
*/
//升序排序
// Integer integer = stream.min((c1, c2) -> c1 - c2).get();
// System.out.println(integer);//1
//降序排序
Integer integer = stream.min((c1, c2) -> c2 - c1).get();
System.out.println(integer);//5
}
6.Matching
allMatch: 只有当流中所有的元素,都匹配指定的规则,才会返回 true
anyMatch: 只要流中有任意的数据,满足指定的规则,都会返回 true
noneMatch: 只有当流中的所有的元素,都不满足指定的规则,才会返回true
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
boolean b = list.stream().allMatch(e -> e > 0);//所有元素都大于0
System.out.println(b);//true
boolean b1 = list.stream().anyMatch(e -> e > 4);//任意一个满足指定的规则
System.out.println(b1);//true
boolean b2 = list.stream().noneMatch(e -> e > 5);
System.out.println(b2);//true 即元素中没有大于5的,都不满足,则返回true
}
7.find
findFirst: 从流中获取一个元素(一般情况下,是获取的开头的元素)
findAny: 从流中获取一个元素(一般情况下,是获取的开头的元素)
这两个方法,绝大部分情况下,是完全相同的,但是在多线程的环境下, findAny和find返回的结果可能不一样。
针对于串行的流,获取的都是第一个元素
针对于并行的流,获取的元素应该不同
演示:
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
//串行的流
Integer integer = list.stream().findFirst().get();
System.out.println(integer);//1
Integer integer1 = list.stream().findAny().get();
System.out.println(integer1);//1
//并行的流 获取的元素不同
Integer integer2 = list.parallelStream().findFirst().get();
Integer integer3 = list.parallelStream().findAny().get();
System.out.println(integer2+" "+integer3);//1 3
}
最终操作,会关闭流,如果一个流被关闭了,再去使用这个流,就出出现异常。
3)中间操作
(1)中间操作的方法
1. filter:过滤出满足条件的数据
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,6,8,5,4,2,39,7,5);
/**
* filter(...) 过滤出来满足条件的数据
* 比如,想要所有的奇数,并遍历出来
*/
list.stream().filter(e->e%2!=0).forEach(System.out::println);
}
2. distinct:去重操作
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,1,1,2,2,2,3,3,3,4,4,4);
System.out.println(list);//[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
//去重操作
list.stream().distinct().forEach(System.out::println);//1 2 3 4
}
3. sorted :排序
public static void main(String[] args) {
List<Integer> list = Arrays.asList(2,5,7,3,6,4,1,9);
System.out.println(list);
//默认升序
list.stream().sorted().forEach(System.out::println);
//降序排序
list.stream().sorted((c1,c2)->c2-c1).forEach(System.out::println);
}
4. limit & skip
limit:截取前几个元素。
skip:跳过前几个元素。
public static void main(String[] args) {
List<Integer> list = Arrays.asList(2,5,7,3,6,4,1,9);
System.out.println(list);
//获得前两个元素
list.stream().limit(2).forEach(System.out::println);
//跳过前三个元素,遍历后面的元素
list.stream().skip(3).forEach(System.out::println);
}
5.map &mapToInt
map(.....) :将元素映射值另外一种类型
public static void main(String[] args) {
List<Integer> list = Arrays.asList(2,5,7,3,6,4,1,9);
List<String> collect = list.stream().map(e -> "" + e).collect(Collectors.toList());
System.out.println(collect);
}
mapToInt(.....) : 将元素映射成intStream
mapToLong(.....):将元素映射成LongStream
mapToDouble(.....):将元素映射成DoubleStream
public static void main(String[] args) {
List<Integer> list = Arrays.asList(2,5,7,3,6,4,1,9);
//求元素的总和
int sum = list.stream().mapToInt(e -> e).sum();
System.out.println(sum);
Integer integer = list.stream().reduce((a, b) -> (a + b)).get();
System.out.println(integer);
}
6.flatMap:扁平式映射
一般传入一个lambda表达式:e->e.stream()
一般针对的都是集合元素仍然是一个集合。
普通的集合 [1,2,3,4,5]
集合元素是集合的: [[1,2],[1,3,4],[2,4,5]]
扁平式映射:就是将元素是集合的这种特殊集合,转成普通的集合
如 将 右边的集合 [[1,2,10],[1,3,4],[2,4,5]] 转成后面的形式: [1,2,10,1,3,4,2,4,5]
public static void main(String[] args) {
List<List<Integer>> nums = new ArrayList<>();
nums.add(Arrays.asList(1,2,3));
nums.add(Arrays.asList(10,12,23));
nums.add(Arrays.asList(11,22,33));
List<Integer> collect = nums.stream().flatMap(e -> e.stream()).collect(Collectors.toList());
System.out.println(collect);//[1, 2, 3, 10, 12, 23, 11, 22, 33]
}
7.Collectors工具类里的方法:
1.joining() : 将流中的数据拼接成一个字符串,注意:只能操作流中是String的数据
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
String collect = list.stream().collect(Collectors.joining());
System.out.println(collect);//abcd
}
2.summingInt() : 将流中的数据,映射成 int 类型的数据,并求和
public static void main(String[] args) {
List<Integer> nums = Arrays.asList(1,2,3,6,5,4);
Integer collect = nums.stream().collect(Collectors.summingInt(e -> e));
System.out.println(collect);
}
3.averagingInt() : 将流中的数据,映射成 int 类型的数据,并求平均值
public static void main(String[] args) {
List<Integer> nums = Arrays.asList(1,2,3,6,5,4);
Double collect = nums.stream().collect(Collectors.averagingInt(e -> e));
System.out.println(collect);
}