一、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表达式:
() -> System.out.println("Hello, Lambda!");
2. 带有参数的表达式:
一个参数:
(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;
}
1.3 Lambda的应用
1.3.1 lambda的应用场景
lambda表达式,只能作用于函数式接口。
函数式接口:就是有且只有一个抽象方法的接口。
1.3.2 案例演示
下面是一些函数式接口:
//里面的抽象方法,没有形参,没有返回值。
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);
}
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编程真简单"*/
@Override
public void Print() {
System.out.println("java编程真简单");
}
}
1.4 变量的捕获
变量的捕获:在内部对外部的变量的引用和访问。
1.4.1 匿名内部类的变量捕获
在Java中,匿名内部类可以捕获外部变量,即在匿名内部类中引用并访问外部作用域的变量。这种行为称为变量捕获(Variable Capturing)。
在匿名内部类中,可以捕获以下类型的变量:
1. 实例变量(成员变量,属性,全局变量):
访问外部类的成员变量:外部类名.this.成员变量 或者直接写
2. 静态变量:访问外部类的静态变量:外部类名.静态变量 或者直接写
3. 方法形参:匿名内部类访问的方法形参,只能访问,不能覆盖。
4. 本地变量(局部变量):匿名内部类访问的局部变量是默认被final修饰的;final修饰的变量只能初始化一次。
匿名内部类访问上述四个变量时,对局部变量(方法形参,本地变量)只能访问,不能覆盖。
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(){
@Override
public 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表达式也是在访问上述四种变量时,对局部变量(方法形参,本地变量)只能访问,不能覆盖。
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) 排序时,使用比较器时。
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集合的迭代
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集合的迭代
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的迭代
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方法即可。
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)优点:
-
简洁性:Lambda表达式提供了一种更简洁、更紧凑的语法,可以减少冗余的代码和样板代码,使代码更易于理解和维护。
-
代码可读性:Lambda表达式使得代码更加自解释和易读,可以直接将逻辑集中在一起,提高代码的可读性和可维护性。
-
便于并行处理:Lambda表达式与Java 8引入的Stream API结合使用,可以方便地进行集合的并行处理,充分发挥多核处理器的优势,提高代码的执行效率。
-
避免匿名内部类的繁琐语法:相比于使用匿名内部类,Lambda表达式的语法更为简洁,减少了冗余的代码,提高了编码效率。
2)缺点:
-
只能用于函数式接口:Lambda表达式只能用于函数式接口(只有一个抽象方法的接口),这限制了它的使用范围。如果需要使用非函数式接口,仍然需要使用传统的方式,如匿名内部类。
-
可读性的折衷:尽管Lambda表达式可以提高代码的可读性,但在某些复杂的情况下,Lambda表达式可能变得难以理解和阅读,特别是当表达式变得过于复杂时。
-
变量捕获的限制:Lambda表达式对捕获的变量有一些限制。它们只能引用final或实际上的最终变量,这可能对某些情况下的代码编写和调试带来一些困扰。
-
学习曲线:对于习惯于传统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():获取的流对象,是并行的,好比有好多个人一起工作,效率高。
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工具类里提供的方法够用。
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亦是如此。
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
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,然后求和。
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
对流中的数据进行遍历,注意遍历完毕,流就关闭了。
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):获取排序后的最后一个元素。
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):获取排序后的第一个元素。
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。
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。
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。
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: 从流中获取一个元素(一般情况下,是获取的开头的元素)
注意:上述两个方法,针对于串行(同步)的流,获取的都是第一个元素。 针对于并行(异步)的流,获取的应该不同,但也可以相同。
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);//1
int 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
过滤出来满足条件的数据,比如想过滤出集合中的所有奇数。
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
去重,去掉集合里重复的数据。
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): 自定义比较规则。
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个元素。
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个元素。
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(.....): 将元素映射成另外一种类型。
比如:将元素映射成字符串类型。
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。
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() 表示压平了。
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() 方法,对流中的数据,进行各种各样的处理、整合。
Collectors.toList() : 将流中的数据,聚合到一个 List 集合中
Collectors.toSet() : 将流中的数据,聚合到一个 Set 集合中
Collectors.toMap() : 将流中的数据,聚合到一个 Map 集合中
maxBy() : 按照指定的规则,找到流中最大的元素,等同于 max
minBy() : 按照指定的规则,找到流中最小的元素,等同于 min
joining() : 将流中的数据拼接成一个字符串,注意:只能操作流中是String的数据
summingInt() : 将流中的数据,映射成 int 类型的数据,并求和
averagingInt() : 将流中的数据,映射成 int 类型的数据,并求平均值
summarizingInt() : 将流中的数据,映射成 int 类型的数据,并获取描述信息
// 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());