Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解

这篇具有很好参考价值的文章主要介绍了Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

相信很多看客都听闻过深拷贝、浅拷贝  , 但是在日常使用的过程中,是否真的有关心过或者遭遇过呢?

不啰嗦,一起来看看。

正文

接下来我通过示例,来复现一下 list.stream浅拷贝 这个事 :

首先是一个对象 Product :
 

/**
 * 产品
 */
@Data
public class Product {

    /**
     * 级别
     */
    private Integer level;
    /**
     * 售价
     */
    private BigDecimal amount;
    /**
     *  库存
     */
    private Long  stockNum;


}

然后是模拟获取到的这个Product的一个list集合数据:
 

    private static  List<Product> getTestList() {
      List<Product> products=new ArrayList<>();
        Product product1=new Product();
        product1.setLevel(100);
        product1.setAmount(new BigDecimal("100"));
        product1.setStockNum(100L);

        Product product2=new Product();
        product2.setLevel(200);
        product2.setAmount(new BigDecimal("200"));
        product2.setStockNum(200L);

        Product product3=new Product();
        product3.setLevel(300);
        product3.setAmount(new BigDecimal("300"));
        product3.setStockNum(300L);

        products.add(product1);
        products.add(product2);
        products.add(product3);
        return products;
    }

接下来做什么, 比如说,我们对这list数据进行按照金额排序输出 以及按照 库存排序输出。

使用了   list.stream().sorted(xxx).collect(Collectors.toList())     

    public static void main(String[] args) {

        List<Product> testList = getTestList();

        List<Product> amountSortList = testList.stream()
                .sorted(Comparator.comparing(Product::getAmount))
                .collect(Collectors.toList());

        List<Product> stockSortList = testList.stream()
                .sorted(Comparator.comparing(Product::getStockNum).reversed())
                .collect(Collectors.toList());
        System.out.println("amountSortList :" +amountSortList.toString());
        System.out.println("stockSortList :" +stockSortList.toString());
    }

看到排序效果是很OK的 : 

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

接下来我们来看看 浅拷贝的问题场景 :

我们对初始数据 list 进行动手脚,看下是否会影响 list.stream() 出来的新的list

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

动手脚 ① ,我们进行新增、删除、清除 这些操作 :
 

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

这时候有没有一些看客在想, 是不是这就是深拷贝呢? 

对原数据操作,新出来的list没有被影响,这不就是深拷贝么?

继续看

动手脚 ②  我们修改 原数据里面的值 :

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

可以看到结果:

受影响了
 

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

到这,我们先不说原因和结论,继续看。

动手脚 ③ 我们修改 第一次list.stream() 出来的list里面的值 :
 

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

这时候,大家可以想下,有啥影响,下面的根据库存排序 用的是 testList 初始数据做排序的。

直接看下效果:

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

定论:

①list.stream 是浅拷贝

② list里面装对象, 无论是 add 、remove 、clear  都不会出现牵连影响

③ list里面装对象, 无论是针对初始list还是新的list, 做了set 编辑修改动作, 都会出现牵连影响

简述原由:

我用几幅图来说下 

图一

list 里面装对象,对象其实都是同一份引用地址,我就故意画成下面这样,希望大家能看清晰些

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

图二 

自己list针对引用product的内存地址引用,多少 与其他list没有关系

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

图三

无论你在哪个list,针对product做set操作,修改值, 那么这对象product内测引用地址,也就是相当于公共财产,大家都引用着, 所以哪里动了,用着的都是受害群体。

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

最后,如果为了避免以上场景出现,我们需要用到list的深拷贝,那么怎么去使用?

深拷贝

简单列举几样:
 

① 序列化 

示例:
 

List<Product> newList = JSON.parseArray(JSON.toJSONString(testList), Product.class);

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解,跟我一起玩转 SpringBoot,spring boot,list,java,深拷贝,浅拷贝

 引用jar:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.69</version>
        </dependency>

② 使用字节流重新生成

    public static <T> List<T> doCopy(List<T> src) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(src);

        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        List<T> dest = (List<T>) in.readObject();
        return dest;
    }

额外需要将实体类实现序列化

public class Product implements Serializable

使用:

        List<Product> newList =doCopy(testList);

③ 用MapperFacade

引入jar:
 

        <dependency>
            <groupId>net.rakugakibox.spring.boot</groupId>
            <artifactId>orika-spring-boot-starter</artifactId>
            <version>1.9.0</version>
        </dependency>

使用:

    @Autowired
    private MapperFacade mapperFacade;



List<Product>  newList = mapperFacade.mapAsList(testList, Product.class);

④使用  MapStruct ,这个不单独列举了

⑤ 手写,循环,new对象,set赋值,再add,这个也不单独列举了

好了,该篇就到这,谢谢。文章来源地址https://www.toymoban.com/news/detail-524209.html

到了这里,关于Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中拷贝list数组如何实现

    要是需要GPT Plus账号的小伙伴可以联系我~ 在Java中,有多种方式可以实现拷贝一个List数组,下面是几种常见的方法: 使用构造函数:可以使用List的构造函数来创建一个新的List,将原始List作为参数传递给构造函数。 使用addAll()方法:可以使用List的addAll()方法将原始List的所有

    2024年02月15日
    浏览(22)
  • list.stream.filter,List<List>转换为List

    可以使用流(Stream)的`flatMap`操作 在这个示例中,我们首先创建了一个嵌套的 List 对象 nestedList ,其中包含了多个 List 。然后,我们使用流的 flatMap 操作将嵌套的 List 展开为一个平铺的 List ,最后使用 collect 方法将结果收集到一个新的 List 对象 flatList 中。最后,我们打印出 f

    2024年02月13日
    浏览(33)
  • java中list对象拷贝至新的list对象并保持两个对象独立的方法

    使用构造函数: 可以使用List的构造函数,传递原始List作为参数来创建一个新的List对象。这样做会创建一个新的List对象,两个List对象互相独立,修改其中一个不会影响另一个。 使用addAll()方法: 可以使用List的addAll()方法将原始List中的所有元素添加到一个新的List中。 使用

    2024年02月07日
    浏览(35)
  • list.stream().forEach()和list.forEach()的区别

    list.stream().forEach() 和 list.forEach() 在 Java 中都是用于遍历集合元素的方法,但它们在使用场景和功能上有所不同: list.forEach() : 是从 Java 8 开始引入到 java.util.List 接口的标准方法。 直接对列表进行迭代,它采用内部迭代的方式,不需要显式创建迭代器。 使用 Lambda 表达式或方

    2024年02月22日
    浏览(28)
  • 对java中的List进行深拷贝,并进行删除测试

    ListString list = new ArrayList();  // 需要拷贝的原始List list.add(\\\"aaa\\\"); list.add(\\\"bbb\\\"); list.add(\\\"ccc\\\"); ListString listNew = new ArrayList();  // 新List // 将原始List的值赋值给新List CollectionUtils.mergeArrayIntoCollection(new Object[list.size()], listNew); Collections.copy(listNew, list); // 现在将心List中的值删除一个,会

    2024年02月11日
    浏览(24)
  • 详细分析Java中的list.foreach()和list.stream().foreach()

    典故来源于项目中使用了两种方式的foreach,后面尝试体验下有何区别! 先看代码示例: 使用List的forEach : 使用Stream API的forEach : 两者输出结果都为如下: 既然两个都输出差不多的结果,但两者还是稍微有些小区别,具体看下文! forEach() 是List接口的一部分,用于对列表中

    2024年04月25日
    浏览(31)
  • java List的stream()方法解析

    一、简介 常用的4种stream()用法。 (1) list.stream().map().collect() 方法,可以获取list中JavaBean的某个字段,转成一个新的list。 (2) list.stream().filter().map().collect() 方法,可以对list中的JavaBean进行筛选,保留符合条件的 JavaBean,然后将JavaBean中的某个字段,转成一个新的list。 (3) list.st

    2024年01月18日
    浏览(33)
  • Java中list集合stream流去重

    准备类: (1)根据单字段name去重 (2)根据多字段name price去重 (3)示例 输出打印结果

    2024年02月09日
    浏览(36)
  • List用Stream流操作ID例子

    具体的Stream用法可以参考:List.stream() 各方法应用_Bulldozer Coder的博客-CSDN博客 用流操作的确简介很多

    2024年02月13日
    浏览(24)
  • 如何使用Stream流将List转换为Map

    以下程序用到的基础代码:

    2024年02月04日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包