【stream流】jdk8特性 list stream流操作合集,optional操作合集

tips: 看标题可能很难理解在说什么,建议结合代码案例看 看了代码一下就能明白了

文章目录

stream流部分

一、当list泛型是一个实体类,需要按照某一个字段进行排序时:

//Comparator.comparing(People::getAge)) 按照年龄排序
// .collect(Collectors.toList()); 将stream流反序列化成list
 List<People> collectList= peopleList.stream()
							 .sorted(Comparator.comparing(People::getAge))
							 .collect(Collectors.toList());
// 倒序 
 List<People> collectList= peopleList.stream()
							 .sorted(Comparator.comparing(People::getAge).reversed())
							 .collect(Collectors.toList());

二、当list泛型是一个单类型的时候 排序(含基本类型):

// sorted() 里面不需要参数 例如:List<LocalDate>dateList = new ArrayList<LocalDate>(); 按照时间排序
 List<LocalDate> collectList = list.stream()
							 .sorted().collect(Collectors.toList());

三、求交集(list共同部分)

List<java.time.LocalDate> resultList= list1.stream()
							.filter(item -> list2.contains(item))
							.collect(Collectors.toList());

四、list转map (当list泛型是个实体类的时候 )

List<People> list = new ArrayList<People>;
Map<String, Integer> collect1 = list .stream().collect(Collectors.toMap(People::getName,People::getAge));

五、list转map (当list泛型是单类型 如基本类型的时候 )

List<LocalDate> dateList = new ArrayList<>();
// p 为固定写法   这样就得到了一个key,value类型都一样的map
 Map<LocalDate, LocalDate> collect1 = dateList.stream().collect(Collectors.toMap((p) -> p, (p) -> p));

六、 list给泛型某个属性统一赋值(stream流的for循环操作)

 list.stream().forEach(item -> item.setXXX(value));
 // 类似的 可以写匿名函数 , stream()也可以不要
 list.stream().forEach(
	item -> {
		if(1==1){
		item.setXxx(xxx);
		}
	}
) 

七、 将list泛型的某个属性提取出来 组成新的list

	List<People> list = new ArrayList();
    List<String> newList= list .stream()
    							.map(People::getId).collect(Collectors.toList());
	

八、取出符合条件的数据到新的list

 List<LineStation> lineStationList = xxx;
 // filter : 过滤器
 List<String> newList= lineStationList.stream().filter(item -> item.getLineId().equals("1")).collect(Collectors.toList());

九、求两个list差集(list1-list2差集)

// 解析:遍历取出每个list1中的元素,且不包含在list2中,重组成一个新的list
List<String> newList= list1.stream().filter(item -> !list2.contains(item)).collect(Collectors.toList());

十、list更换泛型

// demo 其实就是在匿名函数里面自己写逻辑
      Set<PbcDepot> existPbcDepotSet = existPbcDepotList.stream().map(item -> {
            PbcDepot pbcDepot = new PbcDepot();
            pbcDepot.setPbcId(item.getPbcId());
            pbcDepot.setSDepotId(item.getSDepotId());
            pbcDepot.setADepotId(item.getADepotId());
            return pbcDepot;
        }).collect(Collectors.toSet());
基本类型快速更换泛型

简单list:


			List<Long> goodListTemp = xxxx;
			// String::valueOf 演变过程 
			// 1. item -> {return String.valueOf(item)}  
			//2.item -> String.valueOf(item)
			List<String> goodList = goodListTemp.stream().map(
				String::valueOf
			).collect(Collectors.toList());

复杂list:

		// 其中SubletVehicleSchemeVO里面的goodNo是Long类型
		List<SubletVehicleSchemeVO> subletVehicleSchemes = SubletVehicleSchemeWrapper.WRAPPER.entity2Vo(subletVehicleSchemeTemp);
		
		List<String> goodNoList = subletVehicleSchemes.stream().map(item -> String.valueOf(item.getGoodsNo())).collect(Collectors.toList());

十一、list 按某个字段分组

		// groupingBy的那个字段的值 将会作为map的key , 分组的结果作为value
		// 注意groupingBy的那个字段的所有值 不能有null
        List<CompanyParameterVO> topNewList = new ArrayList<>();
        Map<String, List<CompanyParameterVO>> resultMap = 
    		topNewList.stream()
			.collect(Collectors.groupingBy(CompanyParameterVO::getParameterBelong));


十二、list 按某个字段分组后相加聚合

    // 举个不太恰当的场景:数据库中 存的时间窗口是日期维度  而统计是月份维度
    /**
     *  (正确做法应是select DATE_FORMAT(create_time,'%Y-%m')month from t group by month)
     *   在数据库层面将时间给处理掉 按照月份去排序 ,下面是为了演示stream流的用法:
     *  可以先写sql: select count(*),create_time from t group by t 返回一个mapperList
     *  再利用stream流的foreach :mapperList.stream(item -> {}) 	
     * item.setMonth(item.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM")));
     * 此时得到的list结果示例: [{"month":2022-04,"count":1},{"month":2022-04,"count":1}]
     * 我们需要将同一个month里面的count进行相加聚合
     * 
     */
     // 注意groupingBy字段的值 不能有null值
	Map<String, Integer> mapResult  = mapperList.stream()
	          	  .collect(
		           Collectors.groupingBy(
		           MonthCountDTO::getMonth,
		           Collectors.summingInt(MonthCountDTO::getCount)
		           )
	            )
	// 此时得到的是map 如果直接通过responseBody返回json格式 示例: {"2022-04":2}
	// 也就是说 json原来的key没了 只剩vaule了 这基本不符合我们开发的规范
	// 我们可以手动将聚合结果转成实体类 再转一次
	
        List<MonthCountDTO> result = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : mapResult.entrySet()) {
            MonthCountDTO monthCountDTO = new MonthCountDTO()
                    .setCount(entry.getValue())
                    .setMonth(entry.getKey());
            result.add(monthCountDTO);
        }
        // map是无序的 如果业务中 是统计图那种接口 我们还需要将月份排序一下
                result = result.stream()
                .sorted(Comparator.comparing(MonthCountDTO::getMonth))
                .collect(Collectors.toList());

十三、 求List < Entity > 中 某个字段值的总和

// Entity中含有long number 字段
 Map<String,Entity> map = xxxxxxx;
 Collection<ReservedAmountBo> values = map.values();
 long total= values.stream().mapToLong(Entity::getNumber).sum();

十四、 求List < Entity > 中 某个字段值的最大值 (方法比较多 例举三种)

	// Entity中含有long number 字段
   long asLong = list.stream().mapToLong(People::getAge).max().getAsLong();
   Long long1 = list.stream().map(People::getAge).reduce(Long::max).get();
  
   // 如果是比较时间等字段的最大值 核心是max(Comparator.naturalOrder()) 示例
   List<ZonedDateTime> ls = new ArrayList<>();
   ls.add(ZonedDateTime.now().plusSeconds(1111));
   ls.add(ZonedDateTime.now().plusSeconds(2222));
   ls.add(ZonedDateTime.now().plusSeconds(3333));

   ZonedDateTime zonedDateTime = ls.stream().max(Comparator.naturalOrder()).orElse(null);

十五、 String[] 转List < Long >

     	
	// 首先来段String[] arr 转 List<String>
    List<String> strList = Arrays.stream(arr).collect(Collectors.toList());
	
	// arr转List<Long>
	List<Long> list = Arrays.stream(arr)
                    .map(item -> Long.parseLong(item.trim())).collect(Collectors.toList());

十六、 stream流如何处理嵌套循环 用flatMap代替for for循环

这里以flatMap为例 ,flatMap和map的区别在于 flatMap可以把多个集合数据扁平化,通俗点说就是把原来我们要for for循环的数据给摊平。

   List<List<String>> res = new ArrayList<>();

        List<String> listChild = new ArrayList<>();
        listChild.add("111");
        listChild.add("122");

        List<String> listChild2 = new ArrayList<>();
        listChild2.add("133");
        listChild2.add("144");

        res.add(listChild);
        res.add(listChild2);

        List<String> xx = res.stream().flatMap(
        				item -> item.stream().map(
        						each -> each.replace("1", "xx"))
        							).collect(Collectors.toList());
        // [xxxxxx, xx22, xx33, xx44]
        System.out.println(xx);

十七、 stream流收集成单个对象 (list.get(0))

如果我们使用 list.stream.filter(item -> null != item).collect(Collectors.toList()).get(0) 的方式,
首先得先判断list是否为empty 否则会出现下标越界 , 我们可以用stream流api的方式去获取:


       List<Ademo> list = new ArrayList<>();

        Ademo ademo = new Ademo();
        ademo.setName("11");

        Ademo ademo1 = new Ademo();
        ademo1.setName("22");

        list.add(ademo);
        list.add(ademo1);
		
		// findFirst 返回值是optional  
        Ademo res = list.stream().filter(item -> Objects.equals("11", item.getName())).findFirst().orElse(null);

十八、将两个list泛型中,某个字段值相等的数据提取出来

		// 导入的原始数据
		List<ApplyChannelExcelImportDTO> imports = threadLocalImports.get();
		// 公司列表
		List<SalesCompany> companyList = threadLocalExistCompany.get();

		// 导入原始数据中 在公司列表中不存在的公司名
		List<String> resTemp = imports.stream()
			.map(ApplyChannelExcelImportDTO::getSaleCompanyName)
			.filter(name -> companyList.stream().filter(each -> each != null && StringUtils.isNotBlank(each.getName()))
				.noneMatch(each -> each.getName().equals(name)))
			.collect(Collectors.toList());


尽管如此 复杂的逻辑 建议使用for循环 或者结合for使用 提高可读性 下面是for循环的写法

	   // 导入原始数据
		List<ApplyChannelExcelImportDTO> imports = threadLocalImports.get();
		//  公司列表
		List<SalesCompany> companyList = threadLocalExistCompany.get();

		// 导入成功数据
		List<ApplyChannel> storageList = new ArrayList<>();

		// 导入失败数据
		List<ApplyChannelExcelImportFailDTO> failList = new ArrayList<>();

		ApplyChannelExcelImportFailDTO eachFail;
		for (ApplyChannelExcelImportDTO eachImport : imports) {
			// 导入公司是否存在公司范围内
			boolean existCompany = false;
			// 导入数据是否存在渠道
			boolean existApplyChannel = false;

			for (SalesCompany salesCompany : companyList) {
				if (Objects.equals(eachImport.getSaleCompanyName(), salesCompany.getName())) {
					existCompany = true;
					break;
				}
			}

			if (StringUtils.isNotBlank(eachImport.getApplyChannel())) {
				existApplyChannel = true;
			}
			// 如果导入数据中 公司不存在或渠道为空
			if (!existCompany || !existApplyChannel) {
				eachFail = new ApplyChannelExcelImportFailDTO();
				eachFail.setSaleCompanyName(eachImport.getSaleCompanyName());
				eachFail.setApplyChannel(eachImport.getApplyChannel());

				if (!existCompany) {
					eachFail.setMessage("公司不存在");
				} else {
					eachFail.setMessage("渠道为空");
				}
				failList.add(eachFail);
			} else {
				// 一个类型转换
				ApplyChannel applyChannel = ApplyChannelWrapper.WRAPPER.dto2Entity(eachImport);
				storageList.add(applyChannel);
			}
		}

十九、创建stream对象

tips: 创建stream对象后就可以进行一系列的stream流操作了

// 静态定义
Stream<Integer> stream = Stream.of(1, 2, 3);
// 动态定义  在需要添加元素时  add()
Stream.Builder<String> builder = Stream.builder();
builder.add("test");
Stream<String> stream1 = builder.build();

二十、stream流读取文件

      Path path = Paths.get("C:\\Users\\xxx\\Desktop\\test.txt");
        try {
        	// lines方法里面已经close()了 不必担心
            Stream<String> lines = Files.lines(path);
            List<String> lineStr = lines.collect(Collectors.toList());
            System.out.println(lineStr);

        } catch (IOException e) {
            e.printStackTrace();
        }

二十一、stream流截取n个数

        Stream<Integer> stream = Stream.of(1,2,3);
        // 截取前两个值 list : 1,2
        List<Integer> list = stream.limit(2).collect(Collectors.toList());

二十二、stream流跳过n个元素

  		Stream<Integer> stream = Stream.of(1,2,3);
        // list : 3	
        List<Integer> list = stream.skip(2).collect(Collectors.toList());

二十三、stream流reduce规约

reduce有点抽象 你不知道怎么去和别人解释 但是用起来是真的爽 博主尽可能用同学们能看懂的语言解释
我们直接看代码及其注释:

单个参数:


     	Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
     	// a+b 只是表达一个计算公式 ,表面明stream流里面的所有数字相加
        Optional<Integer> reduce = stream.reduce((a, b) -> a + b);
        // 15
        Integer integer = reduce.get();
		// 在这个简单的加法计算案例中,其实等效于下面代码:
		// 注意:流计算完就关闭 需要再次创建
        Stream<Integer> streamForEach = Stream.of(1, 2, 3, 4, 5);
        AtomicReference<Integer> res = new AtomicReference<>(0);
         streamForEach.forEach(

                item ->{
                    // 相当于 int res += int each , 这里用了atomic 保证原子性
                    res.updateAndGet(v -> v + item);
                }

        );
         // 15
        Integer integer1 = res.get();

	// 小tips 所有lambda表达式都可以改写成方法体形式:
      	Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);
        Optional<Integer> reduce = stream2.reduce((a, b) ->
        {
            System.out.println("一闪一闪亮晶晶");
            // do something
            return a + b;
        });

两个参数:

        Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
        // 第一个参数定义一个数  第二个参数定义方法 表示 额外一个数字10 参与stream流的累加
        Integer add = stream1.reduce(10 , Math::addExact);
        // 25
        System.out.println(add);
        
        // 注意:流计算完就关闭 需要再次创建
		Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);
        // 第一个参数定义一个数  第二个参数定义方法 表示 额外一个数字10 参与stream流的取最大值
        Integer add = stream2.reduce(10 , Math::max);
        // 10
        System.out.println(add);

三个参数:


       Stream<Integer> stream1 = Stream.of(1, 5);
        // 表示额外定义的10 参数累乘,并把结果(50)也参与 max取值
        Integer add = stream1.reduce(10, (a, b) -> a * b, Math::max);
        // 50
        System.out.println(add);

二十四、stream流匹配写法 allMatch、anyMatch 和 noneMatch

allMatch 方法用于判断流中的所有元素是否都满足给定的条件。当流中的所有元素都满足条件时,返回 true;如果存在一个元素不满足条件,则返回 false。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean allEven = numbers.stream()
                         .allMatch(n -> n % 2 == 0);
System.out.println(allEven); // 输出结果: false

anyMatch 方法用于判断流中是否存在至少一个元素满足给定的条件。当流中至少有一个元素满足条件时,返回 true;如果没有元素满足条件,则返回 false。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean hasEven = numbers.stream()
                         .anyMatch(n -> n % 2 == 0);
System.out.println(hasEven); // 

noneMatch: noneMatch 方法用于判断流中的所有元素是否都不满足给定的条件。当流中没有元素满足条件时,返回 true;如果存在一个元素满足条件,则返回 false。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean noneNegative = numbers.stream()
                             .noneMatch(n -> n < 0);
System.out.println(noneNegative); // 输出结果: true

值得注意的是,我们匹配操作 不一定就要返回boolean, stream流操作都是可以结合使用的,如第18点提到的案例, 其实类似 if(true)的链式执行

List<String> resTemp = imports.stream()
			.map(ApplyChannelExcelImportDTO::getSaleCompanyName)
			.filter(name -> companyList.stream().filter(each -> each != null && StringUtils.isNotBlank(each.getName()))
				.noneMatch(each -> each.getName().equals(name)))
			.collect(Collectors.toList());

optional部分

Optional.of(value)

返回一个optional对象,option里面存放我们的value,通过option.get()获取,如果值为空,则报空指针,一般来说 我们既然使用了optional 那基本上都是希望避免空指针的,所以一般不用of

  	    People p= null;
  	    // 报 npe
        Optional<People > optional = Optional.of(p);

Optional.ofNullable(value)

与 of(value)相似,ofNullable()里面可以存放空值,但是我们optional.get()出来的还是一个null, 大概率后续还是会出现空指针 ,什么意思呢? 我们举个例子:

		People p= null;
  	    // 不报 npe
        Optional<People > optional = Optional.ofNullable(p);
        // null
        People p1 = optional.get();
        // 报npe
        p1.setName("用户名");

Optional.ofNullable(value).orElse(new Object())

所以我们一般会结合orElse使用,如果为空 则创建一个新对象

		People p= null;
  	    // 不报 npe
        People p1 = Optional.ofNullable(p).orElse(new People ());
    
        // 不报npe
        p1.setName("用户名");

Optional.ofNullable(value).ifPresent(lambdaMethod)

ifPresent 里面是一个lambda表达式

	People p= new People;

   Optional.ofNullable(p).ifPresent(item ->{
            item.setName("用户名");
        });
	// p.getName() --> 用户名 , 如果p为null 则跳过 也不报错 相当于无事发生
        

Optional.ofNullable(value).map(lambdaMethod).orElse(new Object())

这个应用场景类似于上面,多了一步orElse 意思是当 p 为null时,需要新创建一个对象,注:map是有返回值的

	People p= new People;

    People p1 = Optional.ofNullable(p).map(item ->{
            item.setName("用户名");
            return item;
        }).orElse(new People());
	// p.getName() --> 用户名 , 如果p为null 则跳过 也不报错 相当于无事发生
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孟秋与你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值