环球要闻:Stream流体系
博客园 2023-05-22 21:15:52
【资料图】
视频地址https://www.bilibili.com/video/BV1Cv411372m?
1 Stream流概述
目的:简化集合和数组操作的API,结合了Lambda表达式。
Stream流式思想的核心:
- 先得到集合或者数组的Stream流(就是一根传送带)
- 把元素放上去
- 用这个Stream流简化的API来方便的操作元素
2 Stream流获取
- Stream流的三类方法:
- 获取Stream流
- 创建一条流水线,并把数据放到流水线上准备进行操作。
- 中间方法
- 流水线上的操作。一次操作完毕之后,还可以继续进行其他操作。
- 终结方法
- 一个Stream流只能有一个终结方法,是流水线上的最后一个操作。
- Stream操作集合或者数组的第一步是先得到Stream流,然后才能使用流的功能。
- 集合获取Stream流的方式使用Collection接口中的默认方法stream()生成流
/***Collection集合获取流********/Collection list = new ArrayList<>();Stream s = list.stream();/*** Map集合获取流*/Map maps = new HashMap<>();//键流Stream keyStream = maps.keySet().stream();// 值流Stream valueStream = maps.values().stream();//键值对流(拿整体)Stream> keyAndValueStream = maps.entrySet().stream();
- 数组获取Stream流的方式
/**数组获取流****/String[] names = {"张三","李四","王五","范二"};Stream nameStream = Arrays.stream(names);Stream nameStream2 = Stream.of(names);
3 Stream流的常用API
3-1 中间操作方法
注意:
- 中间方法也称为非终结方法,调用完成后返回的新的Stream流可以继续使用,支持链式编程。
- 在Stream流中无法直接修改集合、数组中的数据。
示例
- 过滤:查找出以"张"开头的人的名字
list.stream().filter(s->s.startsWith("张")).forEach(s-> System.out.println(s));
- 统计字符串长度为3的蒜素个数
long size = list.stream().filter(s -> s.length() == 3).count();
- limit获取前几个元素
forEach(s -> System.out.println(s)当s和sout内的s是相同元素时,可以简写成System.out::printlnfilter代表开始过滤,->代表开始过滤,
list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(s -> System.out.println(s));list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(System.out::println);
- skip跳过前几个元素
list.stream().filter(s -> s.startsWith("张")).skip(2).forEach(System.out::println);
- Map:加工方法 :第一个方法为原材料,第二个参数是加工后的结果
- 给集合元素前面都加上一个前缀xxx
list.stream().map(s -> "xxxx"+s).forEach(System.out::println);
- 把所有名字都加工成一个学生对象
2为1的简写1、list.stream().map(s -> new Student(s)).forEach(System.out::println);2、list.stream().map(Student::new).forEach(System.out::println);
- 合并流
//public static Stream concat(Stream extends T> a, Stream extends T> b)//两个不同流合并,例如流1是String类型,流2是Integer类型,此时合并后的流需要是流1和流2的父类,即父类可以接收子类Stream s1 = list.stream().filter(s -> s.startsWith("张"));Stream s2 = Stream.of("Java1","Java2");Stream s3 = Stream.concat(s1,s2);s3.distinct().forEach(System.out::println);
3-2 终结操作方法
注意:终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了。
4 Stream流的综合应用
- 新建一个类存储员工信息
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@NoArgsConstructor@AllArgsConstructorpublic class Employee { private String name; private char sex; private double salary; private double bonus; private String punish; //处罚信息}
- 定义两个集合,并向集合中添加元素
List one = new ArrayList<>();one.add(new Employee("猪八戒","男",30000,25000,null));one.add(new Employee("孙悟空","男",25000,1000,"迟到"));one.add(new Employee("沙僧","男",2000,20000,null));one.add(new Employee("小白龙","男",20000,25000,null));List two = new ArrayList<>();two.add(new Employee("武松","男",15000,9000,null));two.add(new Employee("李逵","男",25000,10000,null));two.add(new Employee("西门庆","男",50000,10000,"迟到"));two.add(new Employee("潘金莲","女",3500,1000,"打人"));two.add(new Employee("武大郎","女",20000,0,"偷窃"));
- 筛选两个部门的最高工资的员工信息。新建一个对象Topperformer
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructorpublic class Topperformer { private String name; private double money;//月薪}
// 1、开发1部的最高工资的员工//指定大小规则Topperformer t = one.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())).map(e -> new Topperformer(e.getName(), e.getSalary() + e.getBonus())).get();
// 2、开发2部的最高工资信息// 1)先用max定义规则,比较大小;2)用map进行加工Topperformer t2 = two.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())).map(e -> new Topperformer(e.getName(), e.getSalary() + e.getBonus())).get();
- 统计2个部门的平均月收入,去掉最高工资和最低工资。
//开发1部one.stream().sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())).skip(1).limit(one.size()-2).forEach(e->{//求出总和:剩余员工的工资总和allMoney += e.getBonus()+e.getSalary();});System.out.println("开发1部的平均工资是" +allMoney/(one.size()-2));//开发2部two.stream().sorted((e1,e2)->Double.compare(e1.getSalary()+e1.getBonus(),e2.getSalary()+e2.getBonus())).skip(1).limit(two.size()-2).forEach(employee -> {allMoney2 += employee.getSalary()+employee.getBonus();});System.out.println("开发2的平均月收入是"+allMoney2);
- 统计两个部门的整体平均工资
Stream s1 = one.stream();Stream s2 = two.stream();Stream s3 = Stream.concat(s1, s2);s3.sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())).skip(1).limit(one.size()+two.size()-2).forEach(e ->{allMoney3 += e.getSalary()+e.getBonus();});BigDecimal a = BigDecimal.valueOf(allMoney3);BigDecimal b = BigDecimal.valueOf(one.size()+ two.size()-2);System.out.println("2个部门的整体平均工资是" +a.divide(b,2, RoundingMode.HALF_UP));
整体代码:
package stream_test;import java.math.BigDecimal;import java.math.RoundingMode;import java.util.ArrayList;import java.util.List;import java.util.stream.Stream;public class StreamDemo1 { public static double allMoney; public static double allMoney2; public static double allMoney3; public static void main(String[] args) { List one = new ArrayList<>(); one.add(new Employee("猪八戒","男",30000,25000,null)); one.add(new Employee("孙悟空","男",25000,1000,"迟到")); one.add(new Employee("沙僧","男",2000,20000,null)); one.add(new Employee("小白龙","男",20000,25000,null)); List two = new ArrayList<>(); two.add(new Employee("武松","男",15000,9000,null)); two.add(new Employee("李逵","男",25000,10000,null)); two.add(new Employee("西门庆","男",50000,10000,"迟到")); two.add(new Employee("潘金莲","女",3500,1000,"打人")); two.add(new Employee("武大郎","女",20000,0,"偷窃")); // 1、开发1部的最高工资的员工 //指定大小规则// Employee employee = one.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus()))// .get(); Topperformer t = one.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())) .map(e -> new Topperformer(e.getName(), e.getSalary() + e.getBonus())).get(); System.out.println(t); // 3-2、开发2部的最高工资信息 // 1)先用max定义规则,比较大小;2)用map进行加工 Topperformer topperformer = two.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())) .map(e -> new Topperformer(e.getName(), e.getSalary() + e.getBonus())).get(); System.out.println(topperformer); // 不能在main方法中定义一个局部变量供main方法中的foreach循环使用。 // 因为main方法和foreach属于不同的方法栈,在不同的栈里面跑,互相不能访问。 // 解决办法:共享变量:所有变量都可以访问,属于类 // 2、统计平均工资,去掉最高工资和最低工资 e1在前就是升序,e2在前就是降序 one.stream().sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())). skip(1).limit(one.size()-2).forEach(e->{ //求出总和:剩余员工的工资总和 allMoney += e.getBonus()+e.getSalary(); }); System.out.println("开发1部的平均工资是" +allMoney/(one.size()-2)); // 4-2、开发2部的平均月收入,去掉最高和最低工资。 two.stream().sorted((e1,e2)->Double.compare(e1.getSalary()+e1.getBonus(),e2.getSalary()+e2.getBonus())) .skip(1).limit(two.size()-2).forEach(employee -> { allMoney2 += employee.getSalary()+employee.getBonus(); }); System.out.println("开发2的平均月收入是"+allMoney2); // 3、合并2个集合流 Stream s1 = one.stream(); Stream s2 = two.stream(); Stream s3 = Stream.concat(s1, s2); s3.sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())) .skip(1).limit(one.size()+two.size()-2).forEach(e ->{ allMoney3 += e.getSalary()+e.getBonus(); }); BigDecimal a = BigDecimal.valueOf(allMoney3); BigDecimal b = BigDecimal.valueOf(one.size()+ two.size()-2); System.out.println("2个部门的整体平均工资是" +a.divide(b,2, RoundingMode.HALF_UP)); }}
5 Stream流的收集操作
- 收集Stream流的含义:把Stream流操作后的结果数据转回到集合或者数组中去。流只能使用一次。
- Stream流:方便操作集合/数组的手段。
- 集合/数组:才是开发中的目的。
- 转换成list集合
Stream s1 = list.stream().filter(s ->s.startsWith("张"));//List list1 = s1.toList(); //得到不可变集合List zhangList = s1.collect(Collectors.toList());
- 转换成set集合
Stream s2 = list.stream().filter(s ->s.startsWith("张"));Set zhangList2 = s2.collect(Collectors.toSet());
- 转换成数组
Stream s3 = list.stream().filter(s -> s.startsWith("张"));// Stream转换成数组时,默认转换成Object形式// Object[] arrs = s3.toArray();// 如果非要把object类型转为String类型String[] arrs = s3.toArray(s->new String[s]);// String[] arrs2 = s3.toArray(String[]::new);System.out.println(arrs); //输出数组的地址System.out.println(Arrays.toString(arrs)); //输出数组的值