当前位置: 首页 > news >正文

Lambda表达式与流式编程

一、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编程真简单"*/@Overridepublic 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(){@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表达式也是在访问上述四种变量时,对局部变量(方法形参,本地变量)只能访问,不能覆盖。

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)优点:

  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():获取的流对象,是并行的,好比有好多个人一起工作,效率高。

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);//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

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

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()             : 按照指定的规则,找到流中最小的元素,等同于  minjoining()           : 将流中的数据拼接成一个字符串,注意:只能操作流中是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());

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 开发笔记:uniapp+vue+微信小程序 picker +后端 省市区三级联动
  • 超精细CG杰作:8K壁纸级官方艺术插画,展现极致美丽与细节的汉服女孩
  • nginx实战演练
  • Vue3核心探索:深入解析组合式API中的mount方法
  • 保研考研机试攻略:第三章——数学(1)
  • 代码随想录算法训练营 | 动态规划 part05
  • 设计模式解析:组合模式与装饰模式
  • php7.4二进制安装-contos7
  • HoloLens 和 Unity 空间坐标系统 Coordinate systems
  • 信号signal与信号量semaphore的区别
  • 基于STM32开发的智能植物浇水系统
  • 音视频相关知识
  • 算法的学习笔记—链表中倒数第 K 个结点(牛客JZ22)
  • 激光雷达点云投影到图像平面
  • CSS方向选择的艺术:深入探索:horizontal和:vertical伪类
  • Python 反序列化安全问题(二)
  • vue总结
  • 浮现式设计
  • 力扣(LeetCode)56
  • 前端面试题总结
  • 一些关于Rust在2019年的思考
  • 原生 js 实现移动端 Touch 滑动反弹
  • puppet连载22:define用法
  • 数据库巡检项
  • ​Linux·i2c驱动架构​
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (js)循环条件满足时终止循环
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (纯JS)图片裁剪
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (一)Neo4j下载安装以及初次使用
  • (转)平衡树
  • .FileZilla的使用和主动模式被动模式介绍
  • .Net 高效开发之不可错过的实用工具
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .net和php怎么连接,php和apache之间如何连接
  • .NET实现之(自动更新)
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d
  • /var/log/cvslog 太大
  • @configuration注解_2w字长文给你讲透了配置类为什么要添加 @Configuration注解
  • @vue/cli 3.x+引入jQuery
  • [ vulhub漏洞复现篇 ] AppWeb认证绕过漏洞(CVE-2018-8715)
  • [51nod1610]路径计数
  • [ACP云计算]易混淆知识点(考题总结)
  • [element-ui] el-dialog 中的内容没有预先加载,因此无法获得内部元素的ref 的解决方案
  • [FROM COM张]如何解决Nios II SBTE中出现的undefined reference to `xxx'警告
  • [GESP202312 四级] 田忌赛马
  • [hdu 2896] 病毒侵袭 [ac自动机][病毒特征码匹配]
  • [Java][算法 双指针]Day 02---LeetCode 热题 100---04~07