Lambda表达式与流式编程

server/2024/9/20 7:20:39/ 标签: 开发语言, java, 笔记, javase, intellij-idea

一、Lambda表达式

1.1 什么是lambda表达式

Lambda表达式是 jdk1.8 引入的一个新特性,它是函数式编程在Java中的一种体现。也是1.8最值得学习的新特性。

1. Lambda表达式实际上就是匿名内部类的简化版本。

2. Lambda表达式是jdk1.8引入的一个最重要的新特性,另外一个就是集合的流式编程。

3. Lambda表达式是java为了扩展函数式编程引入的。

4. Lambda表达式也可以理解为是一个匿名函数(匿名方法:方法没有名字)。

5. Lambda表达式只能作用于函数式接口(有且只有一个抽象方法的接口)。

1.2 Lambda基础语法

1.2.1 语法解析

(parameters) -> expression

或者

(parameters) -> { statements;}

解析:

箭头(->)将参数与Lambda主体分隔开来。

参数部分:1.参数可以是任意合法的Java参数列表,可以为空或包含一个或多个参数。

                  2.参数列表的类型名可以省略。 不能出现有些省略了,有些没有省略的情况。

                  3.如果参数列表中,参数的数量有且只有一个,则小括号可以省略

Lambda主体:

1.Lambda主体可以是一个表达式,表达式外的大括号,可加可不加。 没有大括号时,return关键字必须省略

2.也可以是一个代码块。将按照常规的Java语法执行,并且您可能需要使用return语句来返回值。

1.2.2 语法案例

1.无参数的Lambda表达式:

java">() -> System.out.println("Hello, Lambda!");

2. 带有参数的表达式:

java">一个参数:
(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表达式: 

java">(x, y) -> {int sum = x + y;System.out.println("Sum: " + sum);return sum;
}

1.3 Lambda的应用

1.3.1 lambda的应用场景

lambda表达式,只能作用于函数式接口。

函数式接口:就是有且只有一个抽象方法的接口。

1.3.2 案例演示

下面是一些函数式接口:

java">//里面的抽象方法,没有形参,没有返回值。
interface NoParameterNoReturn{void Print();
}
//里面的抽象方法,只有一个形参,没有返回值。
interface OneParameterNoReturn{void Print(String info);
}
//里面的抽象方法,有多个形参,没有返回值。
interface MuilParameterNoReturn{void Print(String info,int age);
}
//里面的抽象方法,没有形参,有返回值。
interface NoParameterReturn{int Calculate();
}
//里面的抽象方法,只有一个形参,有返回值。
interface OneParameterReturn{int Calculate(int a);
}
//里面的抽象方法,有多个形参,有返回值。
@FunctionalInterface //注解是用来校验是否为函数式接口。
interface MuilParameterReturn{int Calculate(int a,int b);
}
java">public class _02LambdaDemo01 implements NoParameterNoReturn{public static void main(String[] args){/*2. 测试实现类*/_02LambdaDemo01 obj = new _02LambdaDemo01();obj.Print();/*3. 使用匿名内部类的方式,实现NoParameterNoReturn接口,打印"我一定能学会java",并测试*/NoParameterNoReturn npnr = new NoParameterNoReturn() {public void Print(){System.out.println("我一定能学会java");}};npnr.Print();/*4. 使用Lambda表达式的方式,实现NoParameterNoReturn接口,打印"哈哈哈,我哭了...",并测试*/NoParameterNoReturn npnr1 = () -> System.out.println("哈哈哈,我哭了...");npnr1.Print();/*5. 使用Lambda表达式的方式,实现OneParameterNoReturn接口,打印"'我喜欢'+形参",并测试打印,传入'苹果'*/OneParameterNoReturn opnr = (info) -> System.out.println("我喜欢"+info);//一个参数时,形参小括号可以省略opnr.Print("苹果");/*6. 使用Lambda表达式的方式,实现MuilParameterNoReturn接口,打印两个参数拼接的效果,并测试,传入"我今年","18"*/MuilParameterNoReturn mpnr = (info,age) -> System.out.println(info+age);mpnr.Print("我今年",18);/*7. 使用Lambda表达式的方式,实现NoParameterReturn接口,计算两个随机数,区间[25,40]的和,并测试*/// NoParameterReturn npr = ()-> ((int)(Math.random()*16)+25+(int)(Math.random()*16)+25));NoParameterReturn npr = ()-> {int a = (int)(Math.random()*16)+25;int b = (int)(Math.random()*16)+25;System.out.println(a);System.out.println(b);return a+b;};System.out.println(npr.Calculate());/*8. 使用Lambda表达式的方式,实现OneParameterReturn接口,计算形参的立方,并测试传入3*/OneParameterReturn opr = (a) -> {int sum = (int)(Math.pow(a,3));return sum;};System.out.println(opr.Calculate(3));/*9. 使用Lambda表达式的方式,实现MuilParameterReturn接口,计算两个形参的立方和,并测试传入3和4*/MuilParameterReturn mpr = (a1,b1) -> {int sum = a1*a1*a1+b1*b1*b1;return sum;};System.out.println(mpr.Calculate(3,4));}/*1.使用实现类的方式,实现NoParameterNoReturn接口,打印"java编程真简单"*/@Overridepublic void Print() {System.out.println("java编程真简单");}
}

 1.4 变量的捕获

变量的捕获:在内部对外部的变量的引用和访问。

1.4.1 匿名内部类的变量捕获

在Java中,匿名内部类可以捕获外部变量,即在匿名内部类中引用并访问外部作用域的变量。这种行为称为变量捕获(Variable Capturing)。

在匿名内部类中,可以捕获以下类型的变量:

1. 实例变量(成员变量,属性,全局变量):

访问外部类的成员变量:外部类名.this.成员变量 或者直接写

2. 静态变量:访问外部类的静态变量:外部类名.静态变量 或者直接写

3. 方法形参:匿名内部类访问的方法形参,只能访问,不能覆盖。

4. 本地变量(局部变量):匿名内部类访问的局部变量是默认被final修饰的;final修饰的变量只能初始化一次。

匿名内部类访问上述四个变量时,对局部变量(方法形参,本地变量)只能访问,不能覆盖。

java">public class _01InnerClassDemo {private int a;//实例变量private static int b;//静态变量static{b = 2;}public _01InnerClassDemo(){a = 1;}public void m1(int c){int d = 4;//本地变量(局部变量)MyTest mt = new MyTest(){@Overridepublic void test1() {//访问外部类的成员变量:外部类名.this.成员变量   或者直接写System.out.println("instance variable:  "+a);//访问外部类的静态变量:外部类名.静态变量   或者直接写System.out.println("static variable:  "+b);//匿名内部类访问的方法形参,只能访问,不能覆盖。System.out.println("method variable:  "+c);//匿名内部类访问的局部变量是默认被final修饰的;final修饰的变量只能初始化一次。System.out.println("native variable:  "+d);}};mt.test1();}public static void main(String[] args) {//测试:创建外部类对象,调用m1方法。_01InnerClassDemo c1 = new _01InnerClassDemo();c1.m1(3);}
}
interface MyTest{void test1();
}

1.4.2 Lambda表达式的变量捕获

在Lambda表达式中,同样可以捕获外部作用域的变量。Lambda表达式可以捕获以下类型的变量:

1. 实例变量(成员变量,属性,全局变量):

访问外部类的成员变量:外部类名.this.成员变量 或者直接写

2. 静态变量:访问外部类的静态变量:外部类名.静态变量 或者直接写

3. 方法形参:访问的方法形参,只能访问,不能覆盖。

4. 本地变量(局部变量):访问的局部变量是默认被final修饰的;final修饰的变量只能初始化一次。

注意:lambda表达式也是在访问上述四种变量时,对局部变量(方法形参,本地变量)只能访问,不能覆盖。

java">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 variable:  "+c);//访问的局部变量是默认被final修饰的;final修饰的变量只能初始化一次。System.out.println("native variable:  "+d);};mt.test1();}public static void main(String[] args) {//测试:创建外部类对象,调用m1方法。_01InnerClassDemo c1 = new _01InnerClassDemo();c1.m2(3);}
}
interface MyTest{void test1();
}

1.5 Lambda表达式在集合中的应用

1) 排序时,使用比较器时。

java">List<String> list = new ArrayList<String>();
list.add("michael");
list.add("david");
list.add("bob");
list.add("lucy");
//按照字符串的长度降序:比较器使用了lambda表达式的方法。
Collections.sort(list,(a,b)->b.length()-a.length());
System.out.println(list);
运行结果:
[michael, david, lucy, bob]

2)forEach迭代元素

forEach(Consumer c)的源码:

for(T t:this){

        c.accept()

}

Consumer是一个函数式接口:里面只有一个抽象方法  void accept(T t)  

因此只需要向forEach()方法中传入accept的匿名函数,也就是lambda表示即可。

1. List集合的迭代

java">Integer[] arr = new Integer[]{4,5,10,7,2};
List<Integer> nums = Arrays.asList(arr);
for (Integer num : nums) {System.out.println(num);
}
nums.forEach(num -> System.out.println(num));
//继续简化
nums.forEach(System.out::println);

2. Set集合的迭代

java">Integer[] arr = new Integer[]{4,5,10,7,2};
List<Integer> nums = Arrays.asList(arr);
Set<Integer> set = new HashSet<>(nums);
set.forEach(System.out::println);

3. Map的迭代

java">Map<String, Integer> map = new HashMap<>();
map.put("张三", 18);
map.put("李四", 19);
map.put("王五", 17);
map.put("赵六", 20);
//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(value -> System.out.println(value));

3)根据条件移除元素

removeIf(Predicate filter): 满足过滤条件就会删除。

源码解析: 内部逻辑就是一个迭代器遍历集合,根据条件做删除操作, 条件就是filter的test方法。 Predicate是一个函数式接口,里面有boolean test(T t)方法,因此我们在使用时就是写一个lambda表达式来实现test方法即可。

java">List<Integer> ages = Arrays.asList(18,19,17,20,17);
List<Integer> ages2 = new ArrayList<>(ages);
ages2.removeIf(m -> m.equals(17));
System.out.println(ages2);

1.6 Lambda表达式的优缺点

Lambda表达式在Java中引入了函数式编程的概念,具有许多优点和一些限制。下面是Lambda表达式的主要优点和缺点。

1)优点:

  1. 简洁性:Lambda表达式提供了一种更简洁、更紧凑的语法,可以减少冗余的代码和样板代码,使代码更易于理解和维护。

  2. 代码可读性:Lambda表达式使得代码更加自解释和易读,可以直接将逻辑集中在一起,提高代码的可读性和可维护性。

  3. 便于并行处理:Lambda表达式与Java 8引入的Stream API结合使用,可以方便地进行集合的并行处理,充分发挥多核处理器的优势,提高代码的执行效率。

  4. 避免匿名内部类的繁琐语法:相比于使用匿名内部类,Lambda表达式的语法更为简洁,减少了冗余的代码,提高了编码效率。

2)缺点:

  1. 只能用于函数式接口:Lambda表达式只能用于函数式接口(只有一个抽象方法的接口),这限制了它的使用范围。如果需要使用非函数式接口,仍然需要使用传统的方式,如匿名内部类。

  2. 可读性的折衷:尽管Lambda表达式可以提高代码的可读性,但在某些复杂的情况下,Lambda表达式可能变得难以理解和阅读,特别是当表达式变得过于复杂时。

  3. 变量捕获的限制:Lambda表达式对捕获的变量有一些限制。它们只能引用final或实际上的最终变量,这可能对某些情况下的代码编写和调试带来一些困扰。

  4. 学习曲线:对于习惯于传统Java编程风格的开发者来说,Lambda表达式是一项新的概念,需要一定的学习和适应过程。

二、集合的流式编程

2.1 流式编程的简介

流式编程是JDK1.8之后出现的新特性,也是JDK1.8新特性中最值得学习的两种新特性之一。(另外一个是 lambda表达式)。

Stream是对集合操作的增强,流不是集合的元素,不是一种数据结构,不负责数据的存储的。流更像是 一个迭代器,可以单向的遍历一个集合中的每一个元素,并且不可循环。

2.2 为什么要使用集合的流式编程

1.传统方式,如果对集合中的元素做处理时,可能要书写大量的代码,比如增加,删除,过滤等。

2.集合的流式编程是对传统方式的一种简化操作。

2.3 使用流式编程的步骤

集合的流式编程,分三步:

 --第一步: 获取数据源(关联数据源),返回Stream对象。

 --第二步: 对Stream对象进行各种处理,处理后的结果依然是Stream对象。

--第三步: 对Stream对象的最后整合处理。处理后的结果一般情况下都不再是Stream对象,可能是一个具体的数字,字符串,或者一个新的集合。

 -- 注意:整个过程中,数据源本身并不会发生变化。

2.4 数据源的获取

2.4.1 数据源的介绍

数据源,顾名思义,既是流中的数据的来源。是集合的流式编程的第一步,将数据源中的数据读取到流中,进行处理。

注意:将数据读取到流中进行处理的时候,与数据源中的数据没有关系。也就是说,中间操作对流中的数据进行处理、过滤、映射、排序... ,此时是不会影响数据源中的数据。

2.4.2 数据源的获取

这个过程,其实是将一个容器中的数据,读取到一个流中。因此无论什么容器作为数据源,读取到流中 的方法返回值一定是一个Stream。

1)stream():获取的流对象,是串行的,不是并行的,好比只有一个人工作。

2)parallelStream():获取的流对象,是并行的,好比有好多个人一起工作,效率高。

java">public static void main(String[] args) {List<Integer> nums = new ArrayList<>();nums.add(1);nums.add(2);nums.add(3);nums.add(4);nums.add(5);/*** 如果想要对这个集合进行流式编程,第一步,必须获取数据源(关联数据源)*///1. 获取的流对象,是串行的,不是并行的,好比只有一个人工作。Stream<Integer> stream = nums.stream();//2. 获取的流对象,是并行的,好比有好多个人一起工作,效率高。Stream<Integer> stream1 = nums.parallelStream();
}

2.5 最终操作

2.5.1 最终操作的简介

将流中的数据整合到一起。可以存入一个新的集合,也可以直接对流中的数据遍历,或者统计。

注意事项:

 最终操作,会关闭这个流。流里的数据都会被销毁。如果在关闭流的基础上,继续操作流,会报如下异常:

stream has already been operated upon or closed

2.5.2 最终操作的常用方法

1)collect

1. 收集方法,可以将流的数据搜集成一个新的集合。

2. 该方法的形参是一个Collector接口(非函数式接口),可以用来指定收集规则。

3. 通常情况下,不需要程序员自己实现,Collectors工具类里提供的方法够用。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
//获取数据源
Stream<Integer> stream = nums.stream();
//搜集1:搜集成List集合
List<Integer> c1 = stream.collect(Collectors.toList());
System.out.println(c1 == nums);
//搜集2:搜集成Set集合
//Set<Integer> c2 = stream.collect(Collectors.toSet());
//System.out.println(c2);

 搜集成Map集合:

  Collectors.toMap(KeyMapper,ValueMapper)

  KeyMapper是一个函数式接口,里面有一个R apply(T t)抽象方法,我们就是通过lambda表达式      来重写apply方法。 ValueMapper亦是如此。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
//获取数据源
Stream<Integer> stream = nums.stream();
Map<String,Integer> c3 = stream.collect(Collectors.toMap((e)->"Key"+e, e->e));
System.out.println(c3);
运行结果:
{Key2=2, Key1=1, Key5=5, Key4=4, Key3=3}

2)reduce

将流中的数据按照一定的规则聚合起来。

返回的类型:Optional,需要调用它的get方法,获取里面的数据。

从下面的案例可以得出结论: a变量接收的是数据源中的第一个元素,然后b变量接收的是剩下的元素。 相当于: a-=b

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
Optional<Integer> reduce = stream.reduce((a, b) -> a - b); 
int result = reduce.get();
System.out.println("计算结果:"+result);//-13

3)count

用于统计数据源中的元素数量。

底层源码: return mapToLong(e->1L).sum();

即将元素映射成1,然后求和。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
long count = stream.count();
System.out.println("count = " + count);//count = 5

4)forEach

对流中的数据进行遍历,注意遍历完毕,流就关闭了。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
stream.forEach(num -> System.out.println(num));
stream.forEach(System.out::print);

5)max & min

获取流中的最大的元素、最小的元素。

1. max(Comparator c):获取排序后的最后一个元素。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
int m = stream.max((a,b) -> a - b).get();
System.out.println(m);

2. min(Comparator c):获取排序后的第一个元素。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
int n = stream.min((a,b) -> a - b).get();
System.out.println(n);

6)Matching

1. allMatch: 当数据源中的所有元素都满足匹配条件,才返回true。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
boolean b = nums.stream().allMatch(e -> e < 10);
System.out.println(b);
运行结果:true

2. anyMatch: 当数据源中的任意一个元素满足匹配条件,就返回true。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
boolean b = nums.stream().anyMatch(e -> e < 3);
System.out.println(b);
运行结果:true

3. noneMatch: 当数据源中的所有元素都不满足匹配条件,才返回true。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
boolean b = nums.stream().noneMatch(e -> e < 0);
System.out.println(b);
运行结果:true

7)find

1. findFirst:从流中获取一个元素(一般情况下,是获取的开头的元素)

2. findAny: 从流中获取一个元素(一般情况下,是获取的开头的元素)

注意:上述两个方法,针对于串行(同步)的流,获取的都是第一个元素。 针对于并行(异步)的流,获取的应该不同,但也可以相同。

java">public static void main(String[] args) {List<Integer> nums = new ArrayList<>();nums.add(1);nums.add(2);nums.add(3);nums.add(4);nums.add(5);//串行的流演示int e1 = nums.stream().findFirst().get();System.out.println(e1);//1int e2 = nums.stream().findAny().get();System.out.println(e2);//1//并行的流演示int e3 = nums.parallelStream().findFirst().get();System.out.println("e3: "+e3);int e4 = nums.parallelStream().findAny().get();System.out.println("e4: "+e4);
}

2.6 中间操作

2.6.1 filter

过滤出来满足条件的数据,比如想过滤出集合中的所有奇数。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
nums.add(2);
nums.add(4);
//比如想要所有的偶数
List<Integer> c1 = nums.stream().filter(x -> x % 2 != 0).collect(Collectors.toList());
System.out.println(c1);
运行结果:[1, 3, 5]

2.6.2 distinct

去重,去掉集合里重复的数据。

java">List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
nums.add(2);
nums.add(4);
nums.stream().distinct().forEach(System.out::println);
运行结果:
1
2
3
4
5

2.6.3 sorted

1. sorted():升序排序。

2. sorted(Comparator c): 自定义比较规则。

java">List<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);
nums.add(1);
nums.stream().sorted().forEach(System.out::println);
System.out.println("----------------------------------");
nums.stream().sorted((a,b) -> b - a).forEach(System.out::println);
运行结果:
1
2
3
4
5
----------------------------------
5
4
3
2
1

2.6.4 limit

limit(long size): 表示截取流中的前size个元素。

java">List<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);
nums.add(1);
nums.stream().limit(2).forEach(System.out::println);
运行结果:
3
2

2.6.5 skip

skip(long size): 表示跳过前size个元素。

java">List<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);
nums.add(1);
nums.stream().skip(2).forEach(System.out::println);
运行结果:
5
4
1

2.6.6 map

map(.....): 将元素映射成另外一种类型。

比如:将元素映射成字符串类型。

java">List<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);
nums.add(1);
List<String> c1 = nums.stream().map(e -> ""+e).collect(Collectors.toList());

2.6.7 mapToXXX

mapToInt(....):将元素映射成intStream

mapToLong(....):将元素映射成longStream

mapToDouble(....):将元素映射成doubleStream

下面就是将所有元素映射成1。

java">nums.stream().mapToInt(e->1)

2.6.8 flatMap

扁平式映射,一般针对的都是集合元素仍然是一个集合。

普通的集合:[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]

flatMap(.....) 传入一个lambda表达式 :e->e.stream() 表示压平了。

java">List<List<Integer>> out = new ArrayList<>();
out.add(Arrays.asList(1,2,3));
out.add(Arrays.asList(4,5,6));
out.add(Arrays.asList(3,4,5));
long count = out.stream().flatMap(e->e.stream()).count();
System.out.println(count);
double asDouble = out.stream().flatMap(e->e.stream()).mapToInt(e->e).average().getAsDouble();
System.out.println(asDouble);
int a = out.stream().flatMap(e->e.stream()).mapToInt(e->e).max().getAsInt();
System.out.println(a);
运行结果:
9
3.6666666666666665
6

2.7 Collectors工具类

Collectors是一个工具类,里面封装了很多方法,可以很方便的获取到一个 Collector 接口的实现类对 象,从而可以使用 collect() 方法,对流中的数据,进行各种各样的处理、整合。

java">Collectors.toList() : 将流中的数据,聚合到一个  List 集合中 
Collectors.toSet()  : 将流中的数据,聚合到一个  Set 集合中   
Collectors.toMap()  : 将流中的数据,聚合到一个  Map 集合中
maxBy()             : 按照指定的规则,找到流中最大的元素,等同于  max
minBy()             : 按照指定的规则,找到流中最小的元素,等同于  minjoining()           : 将流中的数据拼接成一个字符串,注意:只能操作流中是String的数据summingInt()        : 将流中的数据,映射成  int 类型的数据,并求和
averagingInt()      : 将流中的数据,映射成  int 类型的数据,并求平均值
summarizingInt()    : 将流中的数据,映射成  int 类型的数据,并获取描述信息
java">// maxBy: 按照指定的规则,找到流中最大的元素,等同于  max
Student max = list.stream().collect(Collectors.maxBy((s1, s2) -> s1.getScore() -s2.getScore())).get();
System.out.println(max);// minBy: 按照指定的规则,找到流中最小的元素,等同于  min
Student min = list.stream()
.collect(Collectors.minBy((s1, s2) -> s1.getScore() -s2.getScore()))
.get();
System.out.println(min);// 将流中的数据,拼接起来
String s1 = list.stream().map(Student::getName).collect(Collectors.joining());
System.out.println(s1);// 将流中的数据,拼接起来,以指定的分隔符进行分隔
String s2 = list.stream().map(Student::getName).collect(Collectors.joining(", "));
System.out.println(s2);// 将流中的数据,拼接起来,以指定的分隔符进行分隔,并添加前缀和尾缀
//第一个参数表示以指定的分隔符进行分隔,第二个表示前缀,第三个表示后缀。
String s3 = list.stream().map(Student::getName).collect(Collectors.joining(", ", "{", "}"));
System.out.println(s3);// 将流中的数据,映射成  int 类型的数据,并求和
int sum = list.stream().collect(Collectors.summingInt(Student::getScore));
System.out.println(sum);// 将流中的数据,映射成  int 类型的数据,并求平均值
double average = list.stream().collect(Collectors.averagingInt(Student::getScore));
System.out.println(average);// 将流中的数据,映射成 int 类型的数据,并获取描述信息
IntSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingInt(Student::getScore));System.out.println(summaryStatistics);
System.out.println(summaryStatistics.getCount());
System.out.println(summaryStatistics.getSum());
System.out.println(summaryStatistics.getMax());
System.out.println(summaryStatistics.getMin());
System.out.println(summaryStatistics.getAverage());


http://www.ppmy.cn/server/102046.html

相关文章

VUE(一)——nextTick

DOM更新循环结束后执行延迟回调&#xff0c;在数据修改以后立即使用该方法可获取更新后的DOM。 &#xff08;*问题1&#xff09;DOM更新循环&#xff1f; VUE中使用异步执行DOM更新&#xff0c;在修改数据之后视图不会立即更新&#xff0c;而是等同一事件循环中的所有数据变化…

Java后端面试题(mq相关)(day9)

目录 为什么用MQ&#xff1f; 异步 、削峰、解耦1. 异步处理2. 解耦3. 削峰填谷 Exchange类型什么是死信队列&#xff1f;如何保证消息的可靠性&#xff1f;RabbitMQ中如何解决消息堆积问题?RabbitMQ中如何保证消息有序性?如何防止消息重复消费&#xff1f;(如何保证消息幂等…

ARM——体系结构

计算机体系结构&#xff1a;冯诺伊曼 哈佛 冯诺依曼结构 冯诺依曼结构&#xff0c;也称冯诺依曼模型或普林斯顿结构&#xff0c;是根据冯诺依曼提出的存储程序概念设计的计算机体系结构。其主要特点包括&#xff1a; 存储程序&#xff1a;指令与数据都…

嵌入式 | 嵌入式 Linux 系统使用摄像头

点击上方"蓝字"关注我们 01、引言 >>> 在嵌入式 Linux 系统使用摄像头 俗话说“眼见为实”,这或许是为什么近年来摄像头在嵌入式系统上快速增长的原因。它们被用于不同的场景,如: 远程监控:典型的例子是闭路电视,监控人员在监视环境(或许你所在的大楼…

web开发环境搭配与创建javaee项目

一.web开发 (1)web开发指的是前端,后端,以及数据库进行交互&#xff0c;前端发送请求到后端&#xff0c;后端经过程序处理后到达数据库&#xff0c;最后在进行后端处理响应回前端。 (2)一次三端交互的doget或者dopost简单请求流程 (3)web开发除了需要前端,后端,数据库开发工具…

C#垃圾处理机制相关笔记

C#编程中的垃圾处理机制主要通过垃圾回收器&#xff08;Garbage Collector&#xff0c;GC&#xff09;实现自动内存管理。C#作为一种托管语言&#xff0c;其垃圾处理机制显著减轻了程序员的内存管理负担&#xff0c;与C语言等非托管语言形成鲜明对比。具体介绍如下&#xff1a;…

ElasticSearch相关知识点

ElasticSearch中的倒排索引是如何工作的&#xff1f; 倒排索引是ElasticSearch中用于全文检索的一种数据结构&#xff0c;与正排索引不同的是&#xff0c;正排索引将文档按照词汇顺序组织。而倒排索引是将词汇映射到包含该词汇的文档中。 在ElasticSearch中&#xff0c;倒排索…

ArrayList 和 LinkedList 的区别是什么

数据结构实现&#xff1a;ArrayList 是动态数组的数据结构实现&#xff0c;而 LinkedList 是双向链表的数据结构实现。随机访问效率&#xff1a;ArrayList 比 LinkedList 在随机访问的时候效率要高&#xff0c;因为 LinkedList 是线性的数据存储方式&#xff0c;所以需要移动指…

greenplum授权

1. 表空间&#xff08;Tablespace&#xff09; CREATE&#xff1a;创建表空间权限USAGE&#xff1a;使用表空间权限 在Greenplum数据库中&#xff0c;表空间&#xff08;Tablespace&#xff09;是用于存储数据库对象的物理位置。以下是表空间相关的授权和相应的语法&#xff…

精武杯的部分复现

标红的为答案 计算机手机部分 1、请综合分析计算机和⼿机检材&#xff0c;计算机最近⼀次登录的账户名是&#xff1f;admin 2.请综合分析计算机和⼿机检材&#xff0c;计算机最近⼀次插⼊的USB存储设备串号是?S3JKNX0JA05097Y 3.请综合分析计算机和⼿机检材&#xff0c;谢弘…

《数据中心网络架构与技术》第七章构建数据中心的逻辑网络

Overlay网络 &#xff0c;Overlay网络即通过在现有Underlay网络上叠加一个软件定义的逻辑网络&#xff0c;解决数据中心网络中诸如大规模虚拟机之间二层互通的问题。 Overlay网络和Underlay网络完全解耦&#xff0c;将网络虚拟化并构建出面向应用的自适应逻辑网络&#xff0c…

Isaac Sim 11 粒子

注意&#xff1a;omni.particle.system.core 目前正在进行大量更改。使用现有扩展构建的系统需要在 USD Composer 2023.2 版本中。 1.打开粒子扩展 2. 设置透明度 如果材质中使用的图像具有一定范围的透明度&#xff0c;需要启用Fractional Cutout Opacity&#xff08;位置在第…

看demo学算法之 线性回归模型

嗨&#xff01;今天我们来聊聊如何用Python构建一个简单的线性回归模型。这个过程就像给数据配对舞一样&#xff0c;让它们在舞池里找到最佳位置。准备好了吗&#xff1f;让我们开始吧&#xff01;&#x1f680; 第一步&#xff1a;数据准备 首先&#xff0c;我们要准备一些数…

山西大同大学学生公寓管理系统boot--论文pf

TOC springboot455山西大同大学学生公寓管理系统boot--论文pf 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科…

我问GPT flutter

flutter可以开发android 和ios吗 ChatGPT 说&#xff1a; ChatGPT 是的&#xff0c;Flutter 可以同时开发 Android 和 iOS 应用程序。Flutter 是一个由 Google 开发的开源 UI 工具包&#xff0c;用于构建高性能、跨平台的应用程序。使用 Flutter&#xff0c;你可以用一套代码…

linux更换为阿里云的yum下载镜像源

更换镜像源 1.备份&#xff1a; sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.创建一个文件: cd /etc/yum.repos.d/ touch CentOS-Base.repo 3.往CentOS-Base.repo添加内容 vi CentOS-Base.repo 添加以下内容&#xff1a; [base…

高级java每日一道面试题-2024年8月15日-设计模式篇-设计模式与面向对象原则的关系是什么?

如果有遗漏,评论区告诉我进行补充 面试官: 设计模式与面向对象原则的关系是什么&#xff1f; 我回答: 在设计模式与面向对象原则的关系中&#xff0c;两者紧密相连且相互促进。面向对象的原则为设计模式的形成提供了理论基础和指导思想&#xff0c;而设计模式则是这些原则在…

webrtc学习笔记3

Nodejs实战 对于我们WebRTC项目而言&#xff0c;nodejs主要是实现信令服务器的功能&#xff0c;客户端和服务器端的交互我们选择websocket作为通信协议&#xff0c;所以以websocket的使用为主。 web客户端 websocket WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行…

后端开发刷题 | 二分查找

描述 请实现无重复数字的升序数组的二分查找 给定一个 元素升序的、无重复数字的整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff08;下标从 0 开始&#xff09;&#xff0c;否则返回 -1 数据范…

11、常见API

01、String类概述及构造方法简介 一、字符串 由多个字符组成的一串数据 二、简介 String类代表的是一个字符串。字符串对象在开发中是最常见的。为了方便我们对字符串进行操作&#xff0c;java就把字符串用对象进行了封装&#xff0c;这个封装就是String类 三、String类的构造方…