在具体的介绍之前,先总结一波常用的写法,有基础的可以直接拿来用,没有基础的可以先跳过,看完下面的基础再回来看
List<User> userList = new ArrayList<>();
userList.addAll(Arrays.asList(
new User(1, 11, "张三"),
new User(1, 11, "张三"),
new User(2, 22, "李四"),
new User(1, 33, "王五"),
new User(2, 44, "赵六"),
new User(2, 44, "赵六")));
//----------------------------------------------中间操作----------------------------------------------
//【filter】从列表中筛选出性别为女的数据
List<User> filterUsage = userList.stream().filter(s->s.getSex() == 2).collect(Collectors.toList());
//结果:[User(sex=2, age=22, name=李四), User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六)]
System.out.println(filterUsage);
//【distinct】从列表中去重
List<User> distinctUsage = userList.stream().distinct().collect(Collectors.toList());
//结果:[User(sex=1, age=11, name=张三), User(sex=2, age=22, name=李四), User(sex=1, age=33, name=王五), User(sex=2, age=44, name=赵六)]
System.out.println(distinctUsage);
//【sorted】按照年龄字段从大到小重新排序 (从小到大就是s1.getAge()-s2.getAge())
List<User> sortedUsage = userList.stream().sorted((s1,s2)->s2.getAge()-s1.getAge()).collect(Collectors.toList());
//结果:[User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六), User(sex=1, age=33, name=王五), User(sex=2, age=22, name=李四), User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三)]
System.out.println(sortedUsage);
//【limit】获取前两条数据
List<User> limitUsage = userList.stream().limit(2).collect(Collectors.toList());
//结果:[User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三)]
System.out.println(limitUsage);
//【skip】跳过前两条,之后获取前三条数据
List<User> skipUsage = userList.stream().skip(2).limit(3).collect(Collectors.toList());
//结果:[User(sex=2, age=22, name=李四), User(sex=1, age=33, name=王五), User(sex=2, age=44, name=赵六)]
System.out.println(skipUsage);
//【map】获取所有人的姓名
List<String> mapUsage = userList.stream().map(User::getName).collect(Collectors.toList());
//结果:[张三, 张三, 李四, 王五, 赵六, 赵六]
System.out.println(mapUsage);
//【flatMap】
//【Collectors工具类一些常用方法】
//【groupingBy】分组
// 将集合中的数据按照姓名分组
Map<String, List<User>> groupingByUsage = userList.stream().collect(Collectors.groupingBy(s -> s.getName()));
//结果:{李四=[User(sex=2, age=22, name=李四)], 张三=[User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三)],
// 王五=[User(sex=1, age=33, name=王五)], 赵六=[User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六)]}
System.out.println(groupingByUsage);
// 将集合中的数据按照姓名+性别分组
Map<String, List<User>> groupingByUsage2 = userList.stream().collect(Collectors.groupingBy(s -> s.getName() + "#" + s.getSex()));
//结果:{张三#1=[User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三)], 李四#2=[User(sex=2, age=22, name=李四)],
// 赵六#2=[User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六)], 王五#1=[User(sex=1, age=33, name=王五)]}
System.out.println(groupingByUsage2);
//【maxBy】获取集合中年龄最大的对象信息
User maxByUsage = userList.stream().collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge())).get();
//结果:User(sex=2, age=44, name=赵六)
System.out.println(maxByUsage);
//【minBy】获取集合中年龄最小的对象信息
User minByUsage = userList.stream().collect(Collectors.minBy((s1, s2) -> s1.getAge() - s2.getAge())).get();
//结果:User(sex=1, age=11, name=张三)
System.out.println(minByUsage);
//【joining】拼接集合中所有的用户名称---直接拼接
String joiningUsage = userList.stream().map(User::getName).collect(Collectors.joining());
//结果:张三张三李四王五赵六赵六
System.out.println(joiningUsage);
//拼接中间加上逗号
String joiningUsage2 = userList.stream().map(User::getName).collect(Collectors.joining(","));
//结果:张三,张三,李四,王五,赵六,赵六
System.out.println(joiningUsage2);
//拼接中间加上逗号,两边加上前后缀
String joiningUsage3 = userList.stream().map(User::getName).collect(Collectors.joining(",","[","]"));
//结果:[张三,张三,李四,王五,赵六,赵六]
System.out.println(joiningUsage3);
//【counting】获取集合中对象的数量
Long countingUsage = userList.stream().collect(Collectors.counting());
//结果:6
System.out.println(countingUsage);
//【summingInt】获取集合中所有对象年龄的和
int summingIntUsage = userList.stream().collect(Collectors.summingInt(User::getAge));
//结果:165
System.out.println(summingIntUsage);
//【averagingInt】获取集合中所有对象年龄的平均值
Double averagingIntUsage = userList.stream().collect(Collectors.averagingInt(User::getAge));
//结果:27.5
System.out.println(averagingIntUsage);
//【summarizingInt】获取集合中所有对象的数量/和/最大值/最小值/平均值等信息
IntSummaryStatistics summarizingIntUsage = userList.stream().collect(Collectors.summarizingInt(User::getAge));
//结果:IntSummaryStatistics{count=6, sum=165, min=11, average=27.500000, max=44}
System.out.println(summarizingIntUsage);
//----------------------------------------------最终操作----------------------------------------------
//【collect】
//这里不做演示,上面的所有例子中都有用到
//【reduce】将集合中的所有性别字段的值按照相加的规则求乘积
Integer reduceUsage = userList.stream().map(User::getSex).reduce((s1, s2) -> s1 * s2).get();
//结果:8
System.out.println(reduceUsage);
//【count】求集合中对象的数量
long countUsage = userList.stream().count();
//结果:6
System.out.println(countUsage);
//【forEach】遍历出所有的对象的名称
Consumer<String> action = System.out::println;
//结果:张三 张三 李四 王五 赵六 赵六
userList.stream().map(User::getName).forEach(action);
//【max&min】获取集合中所有对象中年龄的最大值和最小值
Integer maxUsage = userList.stream().map(User::getAge).max(Integer::compareTo).get();
//结果:44
System.out.println(maxUsage);
Integer minUsage = userList.stream().map(User::getAge).min(Integer::compareTo).get();
//结果:11
System.out.println(minUsage);
//【Matching -> allMatch、anyMatch、noneMatch】
//allMatch:只有当流中所有的元素,都匹配指定的规则,才会返回true
boolean allMatchUsage = userList.stream().map(User::getAge).allMatch(e -> e >= 44);
//结果:false
System.out.println(allMatchUsage);
//anyMatch:只要流中有任意的数据,满足指定的规则,都会返回true
boolean anyMatchUsage = userList.stream().map(User::getAge).anyMatch(e -> e <= 11);
//结果:true
System.out.println(anyMatchUsage);
//noneMatch:只有当流中所有的元素,都不满足指定的规则,才会返回true
boolean noneMatchUsage = userList.stream().map(User::getAge).noneMatch(e -> e < 11);
//结果:true
System.out.println(noneMatchUsage);
//【find--> findFirst、findAny】【parallelStream并行流、stream串行流】
//findFirst:从流中获取开头第一个元素
User user = userList.stream().findFirst().get();
//结果:User(sex=1, age=11, name=张三)
System.out.println(user);
User user2 = userList.parallelStream().findFirst().get();
//结果:User(sex=1, age=11, name=张三)
System.out.println(user2);
//findAny:单线程是获取第一个元素,多线程可能不一样
User user3 = userList.stream().findAny().get();
//结果:User(sex=1, age=11, name=张三)
System.out.println(user3);
User user4 = userList.parallelStream().findAny().get();
//结果:User(sex=1, age=33, name=王五)
System.out.println(user4);
//【IntStream+summaryStatistics】获取int数组中的最大值
//1.准备一个int数组作为数据源
int[] array = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
//2.读取数据到流中,获取IntStream对象
IntStream intStream = Arrays.stream(array);
//两种方法:(不能一起用,因为是中间操作)
//1. 直接通过IntStream来获取
//System.out.println(intStream.max().getAsInt());
//2. 通过IntSummaryStatistics,里面包括最大/最小/平均/数量等方法
IntSummaryStatistics intSummaryStatistics = intStream.summaryStatistics();
//结果:9
System.out.println(intSummaryStatistics.getMax());
//----------------------------------------------其它操作----------------------------------------------
//【list转数组1】
Integer[] ints = userList.stream().map(User::getAge).toArray(Integer[]::new);
//【list转数组2】
List<String> list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
String[] strings = list.toArray(new String[list.size()]);
//【数组转list】
String[] arrays = {"1", "2", "3"};
List<String> listStrings = Stream.of(arrays).collect(Collectors.toList());
//结果:[1, 2, 3]
System.out.println(listStrings);
//【修改集合中的对象属性的值】
//原值:[User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三), User(sex=2, age=22, name=李四),
// User(sex=1, age=33, name=王五), User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六)]
System.out.println(userList);
userList.forEach(s->{
s.setAge(100);
s.setSex(100);
});
//新值:[User(sex=100, age=100, name=张三), User(sex=100, age=100, name=张三),User(sex=100, age=100, name=李四),
// User(sex=100, age=100, name=王五), User(sex=100, age=100, name=赵六), User(sex=100, age=100, name=赵六)]
System.out.println(userList);
View Code
一、集合流的简介
1. 集合的流式编程的简介
Stream是JDK1.8之后出现的新特性,也是JDK1.8新特性中最值得学习的两种新特性之一(另一个是lambda表达式)Stream是对集合操作的增强,流不是集合的元素,不是一种数据结构,不负责数据的存储的。流更像是一个迭代器,可以单向的遍历一个集合中的每一个元素,并且不可循环。
2. 为什么要使用集合的流式编程
有些时候,对集合中的元素进行操作的时候,需要使用到其他操作的结果。在这个过程中,集合的流式编程可以大幅度的简化代码的数量。将数据源中的数据,读取到一个流中,可以对这个流中的数据进行操作(删除、过滤、映射...)。每次的操作结果也是一个流对象,可以对这个流再进行其它的操作。
3. 使用流式编程的步骤
通常情况下,对集合中的数据使用流式编程,需要经过以下三步:
(1)获取数据源,将数据源中的数据读取到流中
(2)对流中的数据进行各种各样的处理
(3)对流中的数据进行整合处理
在上述三个过程:
(1)过程2中,有若干方法,可以对流中的数据进行各种各样的操作,并且返回流对象本身,这样的操作,被称为中间操作
(2)过程3中,有若干方法,可以对流中的数据进行各种处理,并关闭流,这样的操作,被称为最终操作
在中间操作和最终操作中,基本上所有的方法参数都是函数式接口,可以使用lambda表达式来实现。使用集合的流式编程,来简化代码量。
二、数据源的获取
1. 数据源的简介
数据源,顾名思义,就是流中的数据的来源,是集合的流式编程的第一步,将数据源中的数据读取到流中,进行处理。注意:将数据读取到流中进行处理的时候,与数据源中的数据没有关系。也就是说,中间操作对流中的数据进行处理、过滤、映射、排序...是不会影响到数据源中的数据的。
2. 数据源的获取
这个过程,其实是将一个容器中的数据,读取到一个流中,因此无论什么容器作为数据源,读取到流中的方法返回值一定是一个Stream。
public static void main(String[] args) throws Exception{
//将集合作为数据源,读取集合中的数据到一个流中
collectionDataSource();
//将数组作为数据源,读取数组中的数据到一个流中(使用引用数据类型)
arrayDataSource();
//将数组作为数据源,读取数组中的数据到一个流中(使用基本数据类型)
}
//将集合作为数据源,读取集合中的数据到一个流中
public static void collectionDataSource(){
//1.实例化一个集合
List<Integer> list = new ArrayList<>();
//2.填充元素
Collections.addAll(list,0,1,2,3,4,5,6,7,8,9);
//3.读取集合中的数据,将其读取到流中
//Stream<Integer> stream = list.stream();//同步流
Stream<Integer> integerStream = list.parallelStream();//并发流
//4.输出stream
System.out.println(integerStream);//java.util.stream.ReferencePipeline$Head@4554617c
}
//将数组作为数据源,读取数组中的数据到一个流中
public static void arrayDataSource(){
//1.实例化一个数组
Integer[] array = new Integer[]{0,1,2,3,4,5,6,7,8,9};
//2.读取数组中的数据到流中,得到一个流对象
Stream<Integer> stream = Arrays.stream(array);
//3.输出Stream
System.out.println(stream);
}
//将数组作为数据源,读取数组中的数据到一个流中
//集合中只能存引用数据类型,但是数组中不用
public static void arrayDataSource2(){
//1.实例化一个数组
int[] array = new int[]{0,1,2,3,4,5,6,7,8,9};
//2.读取数组中的数据到流中,得到一个流对象
IntStream stream = Arrays.stream(array);
//3.输出Stream
System.out.println(stream);
}
三、最终操作
将流中的数据整合到一起,可以存入一个集合,也可以直接对流中的数据进行遍历,数据统计...通过最终操作,需要掌握如何从流中提取出来我们想要的信息。
注意事项:最终操作,在执行结束之后,会关闭这个流,流中的所有数据都会被销毁,如果使用一个已经关闭了的流,会出现异常。
最终操作包括:collect、reduce、count、forEach、max&min、Matching、find、IntStream等。
1. collect
将流中的数据收集到一起,对这些数据进行一些处理。最常见的处理,就是将流中的数据存入一个集合。collect方法的参数,是一个collector接口,而且这个接口并不是一个函数式接口,实现这个接口,可以自定义收集的规则。但是,绝大部分情况下,不需要自定义。
直接使用Collectors工具类提供的方法即可。
public class FinalOperation {
public static void main(String[] args) {
collectUsage();
}
//最终操作:collect将流中的数据整合起来,最常见的处理是:读取流中的数据,整合到一个容器中,得到一个集合。
public static void collectUsage(){
//1.读取数据源
Stream<Integer> dataSource = getDataSource();
//2.流中的数据的聚合
//List<Integer> list = dataSource.collect(Collectors.toList());
//System.out.println(list);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
//Set<Integer> set = dataSource.collect(Collectors.toSet());
//System.out.println(set);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
//Map<String, Integer> map = dataSource.collect(Collectors.toMap(i -> i.toString(), i -> i));//i.toString作为键 i作为值
Map<String, Integer> map = dataSource.collect(Collectors.toMap(Object::toString, i -> i));//i.toString作为键 i作为值
System.out.println(map);//{0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9}
}
//数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
public static Stream<Integer> getDataSource(){
//1.准备一个容器
List<Integer> dataSource = new ArrayList<>();
//2.向数据源中添加数据
Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//3.读取数据源中的数据,得到Stream对象
return dataSource.stream();
}
}
View Code
2. reduce
将流中的数据按照一定的规则聚合起来。将流的元素,逐一带入这个方法中,进行运算。最终的运算结果,得到的其实是一个Optional类型,需要使用get()获取到里面的数据
public class FinalOperation {
public static void main(String[] args) {
reduceUsage();
}
public static void reduceUsage(){
//1.读取数据源,得到流对象
Stream<Integer> dataSource = getDataSource();
//2.最终操作 (这里有两个参数,实现了从0到9的和的求值 即p1=0 p2=1 和的结果为1作为p1 再跟p2=2相加,以此类推)
Integer num = dataSource.reduce((p1, p2) -> p1 + p2).get();
//Integer num = dataSource.reduce(Integer::sum).get();
//3.输出
System.out.println(num);//45
}
//数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
public static Stream<Integer> getDataSource(){
//1.准备一个容器
List<Integer> dataSource = new ArrayList<>();
//2.向数据源中添加数据
Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//3.读取数据源中的数据,得到Stream对象
return dataSource.stream();
}
}
View Code
3. count
统计流中的元素数量
public class FinalOperation {
public static void main(String[] args) {
countUsage();
}
public static void countUsage(){
//1.读取数据源,得到流对象
Stream<Integer> dataSource = getDataSource();
//2.最终操作 获取元素数量
Long num = dataSource.count();
//3.输出
System.out.println(num);//10
}
//数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
public static Stream<Integer> getDataSource(){
//1.准备一个容器
List<Integer> dataSource = new ArrayList<>();
//2.向数据源中添加数据
Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//3.读取数据源中的数据,得到Stream对象
return dataSource.stream();
}
}
View Code
4. forEach
迭代、遍历流中的数据
public class FinalOperation {
public static void main(String[] args) {
forEachUsage();
}
public static void forEachUsage(){
//1.读取数据源,得到流对象
Stream<Integer> dataSource = getDataSource();
//2.最终操作 遍历流中的数据 输出
dataSource.forEach(System.out::print);//0123456789
}
//数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
public static Stream<Integer> getDataSource(){
//1.准备一个容器
List<Integer> dataSource = new ArrayList<>();
//2.向数据源中添加数据
Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//3.读取数据源中的数据,得到Stream对象
return dataSource.stream();
}
}
View Code
5. max&min
获取流中的最大/最小元素
public class FinalOperation {
public static void main(String[] args) {
maxAndMinUsage();
}
//按照执行的对象比较的规则去进行大小的比较,然后得出流中最大、最小的数据
public static void maxAndMinUsage(){
//1.读取数据源,得到流对象
Stream<Integer> dataSource = getDataSource();
//2.最终操作 获取流中的最大、最小值
//Integer max = dataSource.max(Integer::compareTo).get();
//System.out.println(max);//9
Integer min = dataSource.min(Integer::compareTo).get();
System.out.println(min);//0
}
//数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
public static Stream<Integer> getDataSource(){
//1.准备一个容器
List<Integer> dataSource = new ArrayList<>();
//2.向数据源中添加数据
Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//3.读取数据源中的数据,得到Stream对象
return dataSource.stream();
}
}
View Code
6. Matching
allMatch:只有当流中所有的元素,都匹配指定的规则,才会返回true
anyMatch:只要流中有任意的数据,满足指定的规则,都会返回true
noneMatch:只有当流中所有的元素,都不满足指定的规则,才会返回true
public static void main(String[] args) {
matchingUsage();
}
public static void matchingUsage(){
//1.读取数据源,获取Stream对象
Stream<Integer> dataSource = getDataSource();
//2.匹配的操作
//boolean b = dataSource.allMatch(e -> e>0);
//System.out.println(b);//false 因为不是集合中所有的元素都大于0 还有一个等于0
//boolean b = dataSource.anyMatch(e -> e >= 9);
//System.out.println(b);//true
boolean b = dataSource.noneMatch(e -> e > 9);
System.out.println(b);//true
}
//数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
public static Stream<Integer> getDataSource(){
//1.准备一个容器
List<Integer> dataSource = new ArrayList<>();
//2.向数据源中添加数据
Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//3.读取数据源中的数据,得到Stream对象
return dataSource.stream();
}
View Code
7. find
findFirst:从流中获取一个元素(是获取的开头元素)
findAny:从流中获取一个元素(一般情况下,是获取的开头的元素)
这两个方法,绝大部分情况下,是完全相同的,但是在多线程环境下,返回结果可能不一样
public static void main(String[] args) {
findUsage();
}
public static void findUsage(){
//1.实例化一个集合
ArrayList<Integer> dataSource = new ArrayList<>();
Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//2.findFirst演示
//Integer integer = dataSource.stream().findFirst().get();//串行流
//Integer integer = dataSource.parallelStream().findFirst().get();//并行流
//System.out.println(integer);//串行流或者是并行流结果都是0
//3.findAny演示
//Integer integer = dataSource.stream().findAny().get();//串行流
Integer integer = dataSource.parallelStream().findAny().get();//并行流
System.out.println(integer);//串行流是0、并行流结果为6 即不一定是0
}
View Code
8. IntStream
主要可以实现获取流中int类型数据的最大值、最小值、平均值、和、数量
还可以获取到一个对流中数据的分析结果(即一次获取所有类型的值)
public static void main(String[] args) {
intStreamUsage();
}
public static void intStreamUsage(){
//1.准备一个int数组作为数据源
int[] array = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
//2.读取数据到流中,获取IntStream对象
IntStream stream = Arrays.stream(array);
//3.输出
//System.out.println(stream.max().getAsInt());//获取最大值 9
//System.out.println(stream.min().getAsInt());//获取最小值 0
//System.out.println(stream.sum());//获取和 45
//System.out.println(stream.count());//获取流中数据个数 10
//System.out.println(stream.average().getAsDouble());//获取流中数据的平均值 4.5
//4.获取到一个对流中数据的分析结果(即一次获取所有类型的值)
IntSummaryStatistics intSummaryStatistics = stream.summaryStatistics();
System.out.println("最大值:"+intSummaryStatistics.getMax()+" 最小值:"+intSummaryStatistics.getMin());//最大值:9 最小值:0
System.out.println("平均值:"+intSummaryStatistics.getAverage()+" 和:"+intSummaryStatistics.getSum());//平均值:4.5 和:45
System.out.println("数量:"+intSummaryStatistics.getCount());//数量:10
}
View Code
四、中间操作
将数据从数据源中读取到流中,就是对流中的数据进行各种各样的操作、处理。中间操作可以连续操作,每一个操作的返回值都是一个Stream对象,可以继续进行其他的操作,直到最终操作。
中间操作主要分为:filter、distinct、sorted、limit&skip、map&flatMap、Collections工具类
1. filter
条件过滤,仅保留流中满足指定条件的数据,其他不满足的数据都会被删除。
//学生类:存储于集合中的数据类型
private static class Student{
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
//这里省略getter、setter、toString方法
}
public static void main(String[] args) {
filterUsage();
}
public static void filterUsage(){
//1. 获取数据源
Stream<Student> dataSource = getDataSource();
//2. 过滤掉集合中成绩不合格的学生信息
dataSource.filter(s -> s.getScore()>=60).forEach(System.out::println);
//Student{name='xiaoming', age=18, score=100}
//Student{name='xiaoming', age=19, score=90}
//Student{name='xiaoming', age=20, score=80}
//Student{name='xiaoming', age=21, score=70}
//Student{name='xiaoming', age=22, score=60}
}
//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
//1.实例化一个集合,存Student对象
ArrayList<Student> arrayList = new ArrayList<>();
//2.添加若干数据
Collections.addAll(arrayList,
new Student("xiaoming",18,100),
new Student("xiaoming",19,90),
new Student("xiaoming",20,80),
new Student("xiaoming",21,70),
new Student("xiaoming",22,60),
new Student("xiaoming",23,50),
new Student("xiaoming",24,40)
);
//3.读取数据源,得到Stream对象
return arrayList.stream();
}
View Code
2. distinct
去除集合中重复的元素,这个方法没有参数,去重的规则与HashSet相同。
(1)比较两个对象的hashcode
(2)使用equals再来对比一下
这里要注意:实体类中需要重写hashcode和equals方法,否则去重可能不会生效
//学生类:存储于集合中的数据类型
private static class Student{
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
//这里省略getter、setter、toString、hashcode、equals方法
}
public static void main(String[] args) {
distinctUsage();
}
public static void distinctUsage(){
//1. 获取数据源
Stream<Student> dataSource = getDataSource();
//2. 去重 要注意实体类Student中需要重写equals和hashCode方法,否则去重不会生效
dataSource.distinct().forEach(System.out::println);
//Student{name='xiaoming1', age=18, score=100}
//Student{name='xiaoming2', age=20, score=80}
//Student{name='xiaoming3', age=21, score=70}
//Student{name='xiaoming4', age=22, score=60}
//Student{name='xiaoming5', age=23, score=50}
//Student{name='xiaoming6', age=24, score=40}
}
//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
//1.实例化一个集合,存Student对象
ArrayList<Student> arrayList = new ArrayList<>();
//2.添加若干数据
Collections.addAll(arrayList,
new Student("xiaoming1",18,100),
new Student("xiaoming1",18,100),
new Student("xiaoming2",20,80),
new Student("xiaoming3",21,70),
new Student("xiaoming4",22,60),
new Student("xiaoming5",23,50),
new Student("xiaoming6",24,40)
);
//3.读取数据源,得到Stream对象
return arrayList.stream();
}
View Code
3. sorted
对流中的数据进行排序
(1)无参:sorted():将流中的数据,按照其对应的类实现的Comparable接口提供的比较规则进行排序
(2)有参:sorted(Comparator<T> comparator):将流中的数据,按照参数接口提供的比较规则进行排序
private static class Student implements Comparable<Student>{
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public int compareTo(Student o) {
return score-o.score;
}
//这里省略getter、setter、toString、hashcode、equals方法
}
public static void main(String[] args) {
sortedUsage();
}
public static void sortedUsage(){
//1. 获取数据源
Stream<Student> dataSource = getDataSource();
//2. 将流中的数据进行排序 (注意实体类要注意实现Comparable接口并重写compareTo方法,否则会报错)
//dataSource.sorted().forEach(System.out::println);
//Student{name='xiaoming6', age=24, score=40}
//Student{name='xiaoming5', age=23, score=50}
//Student{name='xiaoming4', age=22, score=60}
//Student{name='xiaoming3', age=21, score=70}
//Student{name='xiaoming2', age=20, score=80}
//Student{name='xiaoming1', age=18, score=100}
//Student{name='xiaoming1', age=18, score=100}
//3. 对流中的数据按照自定义的规则进行排序 (按照年龄升序排列)
dataSource.sorted((s1,s2)->s1.getAge()-s2.getAge()).forEach(System.out::println);
//Student{name='xiaoming1', age=18, score=100}
//Student{name='xiaoming1', age=18, score=100}
//Student{name='xiaoming2', age=20, score=80}
//Student{name='xiaoming3', age=21, score=70}
//Student{name='xiaoming4', age=22, score=60}
//Student{name='xiaoming5', age=23, score=50}
//Student{name='xiaoming6', age=24, score=40}
}
//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
//1.实例化一个集合,存Student对象
ArrayList<Student> arrayList = new ArrayList<>();
//2.添加若干数据
Collections.addAll(arrayList,
new Student("xiaoming1",18,100),
new Student("xiaoming1",18,100),
new Student("xiaoming2",20,80),
new Student("xiaoming3",21,70),
new Student("xiaoming4",22,60),
new Student("xiaoming5",23,50),
new Student("xiaoming6",24,40)
);
//3.读取数据源,得到Stream对象
return arrayList.stream();
}
View Code
4. limit&skip
limit:限制,截取流中指定数量的元素 skip:跳过流中的指定数量的元素 经常放在一起用
//实体类省略,参考上面即可
public static void main(String[] args) {
limitAndSkipUsage();
}
public static void limitAndSkipUsage(){
//1. 获取数据源
Stream<Student> dataSource = getDataSource();
//2. 获取成绩的前5名
// dataSource.distinct()
// .sorted((s1,s2)->s2.getScore()-s1.getScore())
// .limit(5)
// .forEach(System.out::println);
//3. 获取成绩为3-5名的
dataSource.distinct()
.sorted((s1,s2)->s2.getScore()-s1.getScore())
.limit(5)
.skip(2)
.forEach(System.out::println);
}
//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
//1.实例化一个集合,存Student对象
ArrayList<Student> arrayList = new ArrayList<>();
//2.添加若干数据
Collections.addAll(arrayList,
new Student("xiaoming1",18,100),
new Student("xiaoming1",18,100),
new Student("xiaoming2",20,80),
new Student("xiaoming3",21,70),
new Student("xiaoming4",22,60),
new Student("xiaoming5",23,50),
new Student("xiaoming6",24,40)
);
//3.读取数据源,得到Stream对象
return arrayList.stream();
}
View Code
5. map&flatMap
对流中的数据进行映射,用新的数据替换旧的数据
map最主要,就是来做元素的替换,其实map是一个元素的映射(将流中每一个元素替换成指定的元素)
flatMap也是元素的映射,flatMap是扁平化映射
扁平化映射:一般用在map映射完成后,流中的数据是一个容器,而我们需要对容器中的数据进行处理 此时使用扁平化映射,可以将流中的容器中的数据,直接读取到流中
案例1:
public static void main(String[] args) {
mapUsage();
}
public static void mapUsage(){
//1. 获取数据源
Stream<Student> dataSource = getDataSource();
//2. 实际需求:获取所有学生的名字
//dataSource.map(Student::getName).forEach(System.out::println);
//dataSource.map(s->s.getName()).forEach(System.out::println);
//3. 实际需求:获取所有学生的成绩 注意:泛型中不能是基本数据类型,只能是包装类 即下面的返回值应该为Stream<Integer>
//dataSource.map(Student::getScore).forEach(System.out::println);
//4. 实际需求:获取所有学生的成绩
IntSummaryStatistics intSummaryStatistics = dataSource.mapToInt(Student::getScore).summaryStatistics();
System.out.println(intSummaryStatistics.getMax());
}
//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
//1.实例化一个集合,存Student对象
ArrayList<Student> arrayList = new ArrayList<>();
//2.添加若干数据
Collections.addAll(arrayList,
new Student("xiaoming1",18,100),
new Student("xiaoming1",18,100),
new Student("xiaoming2",20,80),
new Student("xiaoming3",21,70),
new Student("xiaoming4",22,60),
new Student("xiaoming5",23,50),
new Student("xiaoming6",24,40)
);
//3.读取数据源,得到Stream对象
return arrayList.stream();
}
View Code
案例2:
public static void main(String[] args) {
mapUsage();
}
public static void mapUsage(){
//1.实例化一个字符串数组
String[] array = {"hello","world"};
//2.将字符串数组中的数据读取到流中
Stream<String> stream = Arrays.stream(array);
//3.需求:统计字符串数组中所有出现的字符
//stream.map(String::toCharArray).forEach(e->System.out.println(Arrays.toString(e)));
//结果为 [h, e, l, l, o] [w, o, r, l, d] 两个数组 不符合我们的要求
stream.map(s->s.split(""))
.flatMap(Arrays::stream)
.distinct()
.forEach(System.out::println);
//结果为h e l o w r d
}
View Code
6. Collections工具类
Collectors是一个工具类,里面封装了很多方法,可以很方便的获取到一个Collector接口的实现类对象,从而可以使用collect()方法,对流中的数据,进行各种各样的处理、整合。
常用方法:
Collectors.toList() 将流中的数据,聚合到一个List集合中
Collectors.toSet() 将流中的数据,聚合到一个Set集合中
Collectors.toMap() 将流中的数据,聚合到一个Map集合中
maxBy() 按照指定的规则,找到流中最大的元素,等同于max
minBy() 按照指定的规则,找到流中最小的元素,等同于min
joining() 将流中的数据拼接成一个字符串,注意:只能操作流中是String的数据
summingInt() 将流中的数据,映射成int类型的数据,并求和
averagingInt() 将流中的数据,映射成int类型的数据,并求平均值
summarizingInt() 将流中的数据,映射成int类型的数据,并获取描述信息
public static void main(String[] args) {
//1. 准备一个字符串数组,作为数据源
String[] dataSource = {"nihao","wo","shi","xxx"};
//2. 读取数据源中的数据
Stream<String> stream = Arrays.stream(dataSource);
//3. joining方法,只适用于 Stream<String> 这种流
//String collect = stream.collect(Collectors.joining());//拼接
//System.out.println(collect);//nihaowoshixxx
//String collect = stream.collect(Collectors.joining(","));//拼接 按照逗号分隔
//System.out.println(collect);//nihao,wo,shi,xxx
//tring collect = stream.collect(Collectors.joining(",","[","]"));//拼接 带前缀、后缀
//System.out.println(collect);//[nihao,wo,shi,xxx]
//4. summingInt
Integer collect = stream.collect(Collectors.summingInt(String::length));
System.out.println(collect);//13
}
View Code