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

Viewed 373

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<Employee> 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<Employee> 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 Answers

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("")
        .setManager(false)
        .setSomeNumber(2L);
Related