Java 8 Stream 使用总结

本文介绍 Java Stream API 的多种实用技巧,包括筛选、映射、收集、分组及排序等功能,通过具体案例演示如何简化集合操作,提升代码效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前期工作准备,实体类(ParkingLot ,Area ,ParkingLotType,ParkingCarIO),
CombineInfo类用于整合ParkingLot与ParkingCarIO数据

	@Data
	@AllArgsConstructor
	public class ParkingLot { // 停车场
		private Integer id;
		private String parklotName; // 停车场名称
		private Area area; // 所在区域
		private ParkingLotType parkingLotType; // 停车场类型
		private int total; // 总车位
		private int usedNum; // 使用泊位数
	}

	@Data
	@AllArgsConstructor
	public class Area { // 区域信息
		private Integer id;
		private String areaName; // 区域名称
	}
	@Data
	@AllArgsConstructor
	public class ParkingLotType { // 停车场类型
		private Integer id;
		private String parklotTypeName; // 停车场类型名称
	}

	@Data
	@AllArgsConstructor
	public class ParkingCarIO{ // 流水信息表
		private Integer id;
		private String parklotName; // 停车场名称
		private Date inOutTime; // 出场/入场时间
	}

	@Data
	public class CombineInfo{ // 流水表和停车场合并表
		private String parklotName; // 停车场名称
		private Date inOutTime; // 出场/入场时间
		private String areaName; // 所在区域
		private String parklotTypeName; // 停车场类型

		public combineInfo(String parklotName, Date inOutTime, String parklotTypeName, String areaName) {
			this.parklotName = parklotName;
			this.inOutTime = inOutTime;
			this.areaName = areaName;
			this.parklotTypeName = parklotTypeName;
		}
	}
	@Test
	public void Test() {
		Area areaOne = new Area(01,"区域01");
		Area areaTwo = new Area(02,"区域02");
		Area areaThree = new Area(03,"区域03");
		Area areaFour = new Area(04,"区域04");
		
		Date date = new Date();
		ArrayList<ParkingCarIO> carIOList = new ArrayList<>();
		carIOList.add(new ParkingCarIO(01,"一号停车场",date));
		carIOList.add(new ParkingCarIO(01,"一号停车场",date));
		carIOList.add(new ParkingCarIO(01,"二号停车场",date));
		carIOList.add(new ParkingCarIO(01,"三号停车场",date));
		carIOList.add(new ParkingCarIO(01,"三号停车场",date));

		ParkingLotType residentialLand = new ParkingLotType(01,"住宅");
		ParkingLotType commercialLand = new ParkingLotType(02,"商业");

		List<ParkingLot> parkingLotList = new ArrayList<ParkingLot>();
		parkingLotList.add(new ParkingLot(10501, "一号停车场", areaOne,residentialLand,50,30));
		parkingLotList.add(new ParkingLot(10603, "二号停车场", areaTwo,residentialLand,100,70));
		parkingLotList.add(new ParkingLot(40514, "三号停车场",areaThree,residentialLand,100,10));
		parkingLotList.add(new ParkingLot(59562, "四号停车场", areaFour,commercialLand,150,60));
		parkingLotList.add(new ParkingLot(29415, "五号停车场", areaFour,commercialLand,200,100));
		parkingLotList.add(new ParkingLot(61812, "七号停车场", areaTwo,residentialLand,100,50));
		parkingLotList.add(new ParkingLot(61812, "八号停车场", areaTwo,commercialLand,100,50));
		parkingLotList.add(new ParkingLot(61812, "九号停车场", areaOne,commercialLand,100,50));
		parkingLotList.add(new ParkingLot(61812, "十号停车场", areaThree,residentialLand,100,50));
		}

筛选(filter)

筛选,按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

  • 需求1:当需获取某个对象集合中符合条件的数据时,例如,筛选出泊位大于100的停车场
List<ParkingLot> list = parkingLotList.stream()
				.filter(x -> x.total > 100).collect(Collectors.toList()); // x即表示ParkingLot

映射(map/flatMap)

映射,将流中的每个元素按照一定的规则映射为另一种元素

  • 需求1:当需获取对象集合中的某一属性时。例如,从停车场集合中获取各个停车场的名称
List<String> nameList = parkingLotList.stream()
				.map(ParkingLot::getParklotName).collect(Collectors.toList()); // ::方法引用,引用getParklotName方法

结果:[一号停车场, 二号停车场, 三号停车场, 四号停车场, 五号停车场, 六号停车场]

  • 需求2:当需获取对象集合中多个属性时,例如,从所有停车场集合中获取的名称和总泊位数
List<Map> list1 = parkingLotList.stream().map(new Function<ParkingLot, Map>() {
			@Override
			public Map apply(ParkingLot parkingLot) {
				Map<String, Object> map = new HashMap<>();
				map.put("parklotName", parkingLot.getParklotName());
				map.put("total", parkingLot.getTotal());
				return map;
			}
		}).collect(Collectors.toList());

结果:[{total=50, parklotName=一号停车场}, {total=100, parklotName=二号停车场}…]

收集(collect)

收集,将流中的数据中心归集到新的集合中,相当于再整合,常用的有toListtoSettoMap

分组(groupingBy)

  • 需求1:单条件分组,例如,根据街道名称进行分组
Map<String, List<ParkingLot>> collect = parkingLotList.stream()
				.collect(Collectors.groupingBy(x -> x.getArea().getAreaName()));
  • 需求2:多条件分组,例如,根据街道名称与类型名称进行分组
Map<String, Map<String, List<ParkingLot>>> collect1 = parkingLotList.stream()
				.collect(Collectors.groupingBy(x -> x.getArea().getAreaName()
						, Collectors.groupingBy(x -> x.getParkingLotType().getParklotTypeName())));
  • 需求3:分组后,按需设置返回数据的格式,例如,根据街道名称分组后,只保留集合中对象的名称与总数
Map<String, List<Map>> map= parkingLotList.stream()
   			.collect(Collectors.groupingBy(x -> x.getArea().getAreaName(), Collectors.collectingAndThen(Collectors.toList(), m -> {
   				return m.stream().map(new Function<ParkingLot, Map>() {
   					@Override
   					public Map apply(ParkingLot parkingLot) {
   						HashMap<String, Object> map = new HashMap<>();
   						map.put("parklotName", parkingLot.getParklotName());
   						map.put("total", parkingLot.getTotal());
   						return map;
   					}
   				}).collect(Collectors.toList());
   			})));
  • 需求4:对分组后的数据进行计算合并,例如,根据街道名称分组后,获取每组数据中平均占有率
    注意:乘法、除法运算时,使用--BigDecimal
Map<String, Integer> map= parkingLotList.stream().collect(Collectors.groupingBy(x -> x.getArea().getAreaName()
  			, Collectors.collectingAndThen(Collectors.toList(), m -> {
  				int usedSum = m.stream().mapToInt(ParkingLot::getUsedNum).sum(); // 总使用数量
  				int totalSum = m.stream().mapToInt(ParkingLot::getTotal).sum();  // 总数量
  				int avgNum = BigDecimal.valueOf(usedSum).divide(BigDecimal.valueOf(totalSum), 2, BigDecimal.ROUND_HALF_UP).intValue();//分组后,各组的平均占用率
  				return avgNum;
  	})));
  • 需求5:分组,并对分组后的key进行格式化
    注意:乘法、除法运算时,使用--BigDecimal
// 由于表中存储的 评定结果为: 1,2,null 所以,为了前端好接收,特将key改为英文
      Map<String, Long> collect = parkingLotList.stream().collect(Collectors.groupingBy(parkingLot-> {
          if (parkingLot.getArea() != null) {
              if (parkingLot.getArea.getId().equals("1")) {
                  return "pass";
              } else if (parkingLot.getArea.getId().equals("0")) {
                  return "notPass";
              }
          }
          return "weiPingDing";
      }, Collectors.counting()));

排序(sorted)

  • 需求1:对集合进行操作,根据对象的某一属性(int)进行排序。例如,根据停车场的总车位数量进行倒叙排序
    注意: .reversed()倒叙排列 ,需要正序排列去掉.reversed()
List<ParkingLot> resultList = parkingLotList.stream()
                .sorted(Comparator.comparing(ParkingLot::getTotal).reversed())
                .collect(Collectors.toList());
  • 需求2:对Map进行操作,实现排序功能(思路,将Map转换为List),例如,对分组后的数据进行排序时,可用该方法
		Map<String, Integer> map = parkingLotList.stream()
			.collect(Collectors.groupingBy(x -> x.getArea().getAreaName()
                , Collectors.collectingAndThen(Collectors.toList(), m -> {
                    int usedSum = m.stream().mapToInt(ParkingLot::getUsedNum).sum();
                    int totalSum = m.stream().mapToInt(ParkingLot::getTotal).sum();
                    int avgNum = BigDecimal.valueOf(usedSum).divide(BigDecimal.valueOf(totalSum), 2, BigDecimal.ROUND_HALF_UP).intValue();//分组后,各组的平均占用率
                    return avgNum;
                })));

        List<Map<String, Object>> resultList = new ArrayList<>();
        map.forEach((k, v) -> {
            Map<String, Object> temp = new HashMap<>();
            temp.put("name", k);
            temp.put("rate", v);
            resultList.add(temp);
        });
        resultList.sort((e1, e2) -> {
            return Integer.valueOf(e2.get("total").toString()) - Integer.valueOf(e1.get("total").toString());
        });

对两集合进行操作

  • 交集:将两集合中含有某一共同属性的数据筛选出来,并整合出新的集合

CombineInfo是专门创建的类,根据所需属性,创建对应的有参构造方法

List<CombineInfo> list2 = carIOList.stream()
  			.flatMap(x -> parkingLotList.stream()
  					.filter(y -> x.getParklotName().equals(y.getParklotName()))
  					.map(y -> new CombineInfo(x.getParklotName(),x.getInOutTime(), y.getParkingLotType().getParklotTypeName(), y.getArea().getAreaName())))  // 此处为,将筛选出来的进行加工
  			.collect(Collectors.toList());
  • 差集:现有A,B两集合,根据某一共同属性筛选出A有B没有的数据,并整合出新的集合
    注意: 使用 .noneMatch()
List<StatementManagementRequest> collectList = parkList.stream()
              .filter(park -> statementManagementList.stream()
              .noneMatch(stateInfo -> stateInfo.getParkName().equals(park.getParklotName())))
              .map(y -> new StatementManagementRequest(y.getParklotName(),  y.getParkingLotType().getParklotTypeName(), 0, 0, 0, 0, (double) 0, chooseTime, 0))  // 此处为,将筛选出来的进行加工
              .collect(Collectors.toList());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值