【java】集合流式编程总结
在具体的介绍之前,先总结一波常用的写法,有基础的可以直接拿来用,没有基础的可以先跳过,看完下面的基础再回来看
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);
一、集合流的简介
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(); } }
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(); } }
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(); } }
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(); } }
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(); } }
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(); }
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 }
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 }
四、中间操作
将数据从数据源中读取到流中,就是对流中的数据进行各种各样的操作、处理。中间操作可以连续操作,每一个操作的返回值都是一个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(); }
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(); }
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(); }
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(); }
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(); }
案例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 }
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 }
持续更新!!!
注意:本篇文章大多数内容来自bilibili网站千锋教育,地址:https://www.bilibili.com/video/BV1fT4y177ui?p=6 本篇文章仅用于个人学习和总结,如有侵权,联系删除!