Java Stream toArray 对象深拷贝

在Java中,Stream API是一个非常强大和灵活的工具,用于对集合数据进行处理和操作。使用Stream API,我们可以将集合数据进行过滤、映射、排序等操作,使代码更加简洁和可读。在Stream API中,toArray()是一个常用的终端操作,用于将数据流转换为数组。但是,对于包含对象的数据流,需要注意默认情况下toArray()方法返回的是浅拷贝,即数组中的元素和原始数据流中的元素引用的是同一个对象。如果我们希望进行对象的深拷贝,就需要特殊处理。

本文将介绍如何使用Java的Stream API中的toArray()方法进行对象的深拷贝,并通过代码示例进行说明。

浅拷贝和深拷贝

在开始之前,我们先来了解一下浅拷贝和深拷贝的概念。

  • 浅拷贝:将一个对象的引用复制给另一个对象,复制后的对象与原始对象引用的是同一个对象。如果修改复制后的对象,原始对象也会受到影响。

  • 深拷贝:将一个对象复制给另一个对象,复制后的对象与原始对象没有任何关联。修改复制后的对象不会影响原始对象。

在Java中,对于基本类型(如int、float等)的数组,使用Arrays.copyOf()方法可以实现深拷贝。但是对于包含对象的数组,Arrays.copyOf()只能实现浅拷贝。而Stream API中的toArray()方法默认也只能实现浅拷贝,需要我们自己进行处理,才能实现对象的深拷贝。

使用Stream.toArray()实现对象深拷贝

在Java 8中,Stream API引入了toArray()方法,用于将数据流转换为数组。默认情况下,toArray()方法返回的是一个Object数组,其元素与原始数据流中的元素是浅拷贝的关系。为了实现对象的深拷贝,我们可以通过自定义Collector的方式来实现。

下面是一个自定义Collector的示例代码:

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

class DeepCloneCollector<T> implements Collector<T, List<T>, List<T>> {
    @Override
    public Supplier<List<T>> supplier() {
        return ArrayList::new;
    }

    @Override
    public BiConsumer<List<T>, T> accumulator() {
        return List::add;
    }

    @Override
    public BinaryOperator<List<T>> combiner() {
        return (list1, list2) -> {
            list1.addAll(list2);
            return list1;
        };
    }

    @Override
    public Function<List<T>, List<T>> finisher() {
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }
}

在上面的代码中,我们定义了一个DeepCloneCollector类,实现了Collector接口的几个方法。这里我们使用ArrayList作为容器,通过add方法将元素添加到容器中。在combiner方法中,我们将两个容器合并成一个。

通过使用自定义Collector,我们可以将Stream流转换为一个深拷贝的List对象。下面是一个示例代码:

import java.util.*;

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Main {
    public static void main(String[] args) {
        List<Person> persons = Arrays.asList(
                new Person("Alice", 20),
                new Person("Bob", 25),
                new Person("Charlie", 30)
        );

        List<Person> deepCopy = persons.stream().collect(new DeepCloneCollector<>());

        System.out.println(deepCopy);
        // Output: [Person{name='Alice', age=20}, Person{name='Bob', age=25