使用Java 8的流API来进行ArrayList的深拷贝,但是会在编译时出现错误。

huangapple go评论75阅读模式
英文:

Use java 8 stream api to do deep copy of array list but get build time error

问题

我在我的 Spring Boot 项目的模型类中使用了 lombok 库。

@Data
@Builder
public class Employee {

    private String fullname;
    private long someNumber;
    private boolean isManager;
}

在另一个类中,我有一个员工列表:

List<Employee> employeeList = getListOfEmployees();

我想要创建一个 employeeList 的深拷贝,以下是我尝试过的方法:

步骤1:我在 Employee 类中创建了一个拷贝构造函数:

@Data
@Builder
public class Employee {

    private String fullname;
    private long someNumber;
    private boolean isManager;

    // 拷贝构造函数
    public Employee(Employee employee) {
        this.fullname = employee.fullname;
        this.someNumber = employee.someNumber;
        this.isManager = employee.isManager;
    }
}

步骤2:我使用 Java 8 的流 API 来创建员工列表的深拷贝:

List<Employee> employeeListCopy = employeeList.stream().map(Employee::new).collect(Collectors.toList());

但是当我构建我的 Spring Boot 项目时,我遇到了错误:

错误:(13, 1) java: 无法将类 com.my.webapp.model.Employee 中的构造函数应用于给定类型;
  必需的类型:com.my.webapp.Employee
  找到的类型:java.lang.String,long,boolean
  原因:实际参数列表与形式参数列表的长度不同

为什么会出现这个错误?如何消除这个深拷贝的错误?

英文:

I use lombok library in my spring-boot project's model classes.

@Data
@Builder
public class Employee {

    private String fullname;
    private long someNumber;
    private boolean isManager;
}

In another class, I have a list of employees:

List&lt;Employee&gt; employeeList = getListOfEmployees();

I would like to create a deep copy of the employeeList, the following things are what I tried:

step 1. I create a copy constructor in Employee class:

@Data
@Builder
public class Employee {

    private String fullname;
    private long someNumber;
    private boolean isManager;

    // copy constructor
    public Employee(Employee employee) {
        this.fullname = employee.fullname;
        this.someNumber = employee.someNumber;
        this.isManager = employee.isManager;
    }
}

step 2. I use Java 8 stream API to create a deep copy of the list of employees:

List&lt;Employee&gt; employeeListCopy = employeeList.stream().map(Employee::new).collect(Collectors.toList());

But when I build my sprint-boot project, I got error:

Error:(13, 1) java: constructor Employee in class com.my.webapp.model.Employee cannot be applied to given types;
  required: com.my.webapp.Employee
  found: java.lang.String,long,boolean
  reason: actual and formal argument lists differ in length

Why? How to get rid of this error for my deep copy?

答案1

得分: 2

问题不在于 Stream API,而在于 lombok。当你使用 @Builder 时,会调用一个构造函数:

public Employee build() {
    return new Employee(fullname, someNumber, isManager);
}

EmployeeBuilder 内部调用(由 lombok 生成)。由于你已经提供了一个构造函数,lombok 将不会生成另一个构造函数(即:lombok 仅在没有已定义构造函数的情况下为生成器生成所需的构造函数)。解决方案相当简单,将 @AllArgsConstructor 添加到你的类中。

通常情况下,我个人不太喜欢 @Builder,而是使用 @Accessors(chain = true) 替代:

@Setter
@Getter
@Accessors(chain = true)
static class Employee {

    private String fullname;
    private long someNumber;
    private boolean isManager;

    public Employee() {

    }

    // 拷贝构造函数
    public Employee(Employee employee) {
        fullname = employee.fullname;
        someNumber = employee.someNumber;
        isManager = employee.isManager;
    }
}

然后你可以这样做:

Employee emp = new Employee()
        .setFullname("")
        .setManager(false)
        .setSomeNumber(2L);
英文:

The problem is not in the Stream API, but in lombok. When you use @Builder, there will be a call to a constructor:

public Employee build() {
      return new Employee(fullname, someNumber, isManager);
}

from within EmployeeBuilder (that lombok will generate). Since you have already provided a constructor, lombok will not generate another one (i.e.: lombok will only generate the needed constructor for the Builder IFF there is not a constructor already defined). The solution is rather simple, add @AllArgsConstructor to your class.

In general, I personally, am not a fan of @Builder, I use @Accessors(chain = true) instead:

@Setter
@Getter
@Accessors(chain = true)
static class Employee {

    private String fullname;
    private long someNumber;
    private boolean isManager;

    public Employee() {

    }

    // copy constructor
    public Employee(Employee employee) {
        fullname = employee.fullname;
        someNumber = employee.someNumber;
        isManager = employee.isManager;
    }
}

And you can do:

Employee emp = new Employee()
        .setFullname(&quot;&quot;)
        .setManager(false)
        .setSomeNumber(2L);

huangapple
  • 本文由 发表于 2020年4月7日 21:19:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/61080961.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定