Springboot misuses list.stream, encounters list shallow copy sneak attack, actual combat diagram

foreword

I believe that many viewers have heard of deep copy and shallow copy, but in the process of daily use, have they really cared about or encountered it?

Without further ado, let's take a look.

text

Next, I use an example to reproduce the shallow copy of list.stream:

The first is an object Product:
 

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

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


}

Then it is a list collection data of this Product obtained by simulation:
 

    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;
    }

What to do next, for example, we sort and output the list data by amount and by inventory.

Used 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());
    }

It is OK to see the sorting effect: 

Next, let's take a look at the problem scenario of shallow copy:

Let's manipulate the initial data list to see if it will affect the new list from list.stream()

Hands and feet ①, we add, delete, and clear these operations:
 

At this time, are there any spectators wondering, is this a deep copy? 

For the original data operation, the new list is not affected. Isn't this a deep copy?

wrong

keep watching

Hands-on ② We modify the value in the original data:

You can see the result:

affected
 

At this point, let's not talk about the reasons and conclusions, and continue to look.

Hands and feet ③ We modify the value in the list from the first list.stream():
 

At this time, you can think about the impact. The following sorting according to inventory uses the initial data of testList for sorting.

Look directly at the effect:

Conclusion:

①list.stream is a shallow copy

② Objects are installed in the list, whether it is add, remove, or clear, there will be no implicated effects

③ Objects are installed in the list, whether it is for the initial list or a new list, if the set editing and modification action is performed, there will be implicated effects

Brief reason:

Let me illustrate with a few pictures 

Figure 1

There are objects in the list, and the objects are actually the same reference address, so I deliberately drew it as follows, I hope everyone can see it clearly

Figure II 

Your own list refers to the memory address that references the product, how much has nothing to do with other lists

Figure three

No matter which list you are in, if you perform a set operation on the product and modify the value, then the internal test reference address of the product is equivalent to public property, which is referenced by everyone, so where it is moved, it is used by the victim group.

Finally, if in order to avoid the above scenarios, we need to use a deep copy of the list, how to use it?

deep copy

Just to list a few:
 

① Serialization 

Example:
 

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

 Quote jar:

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

② Regenerate using byte stream

    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;
    }

In addition, the entity class needs to be serialized

public class Product implements Serializable

use:

        List<Product> newList =doCopy(testList);

③ 用MapperFacade

Import jar:
 

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

use:

    @Autowired
    private MapperFacade mapperFacade;



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

④ Use MapStruct, this is not listed separately

⑤ Handwriting, looping, new object, set assignment, and then add, this is not listed separately

Well, that's all for this article, thank you.

Guess you like

Origin blog.csdn.net/qq_35387940/article/details/131528858