Home » Java » Split list of objects into multiple lists of fields values using Java streams-Exceptionshub

Split list of objects into multiple lists of fields values using Java streams-Exceptionshub

Posted by: admin February 25, 2020 Leave a comment


Let’s say I have such object:

public class Customer {

    private Integer id;
    private String country;
    private Integer customerId;
    private String name;
    private String surname;
    private Date dateOfBirth;

and I have a List<Customer>. I would like to split such list with Java streams so that I would get a list of ids List<Integer>, countries List<String>, customerIds List<Integer> etc.

I know that I could do it as simple as making 6 streams such as:

List<Integer> idsList = customerList.stream()

but doing it that many times that I have fields seems pretty dull. I was thinking about custom Collector but I could not come up with anything useful that would be both neat and efficient.

How to&Answers:

For a type safe solution, you’d need to define a class holding the desired results. This type may also provide the necessary methods for adding another Customer or partial result:

public class CustomerProperties {
    private List<Integer> id = new ArrayList<>();
    private List<String> country = new ArrayList<>();
    private List<Integer> customerId = new ArrayList<>();
    private List<String> name = new ArrayList<>();
    private List<String> surname = new ArrayList<>();
    private List<Date> dateOfBirth = new ArrayList<>();

    public void add(Customer c) {
    public void add(CustomerProperties c) {

Then, you can collect all results like

CustomerProperties all = customers.stream()
    .collect(CustomerProperties::new, CustomerProperties::add, CustomerProperties::add);


You can create a method like so:

public <T> List<T> getByFieldName(List<Customer> customerList, Function<Customer, T> field){
    return customerList.stream()

Then just call your method with the field you want:

List<Integer> ids = getByFieldName(customerList, Customer::getId);
List<String> countries = getByFieldName(customerList, Customer::getCountry);
List<Integer> customerIds = getByFieldName(customerList, Customer::getCustomerId);


You can use jooR for that:

    .flatMap(el -> Reflect.on(el).fields().entrySet().stream())

This will result in a map that lists all the values for all the fields:

"name" -> ["1", "2"]
"country" -> ["1", "2"]

It’s easy and generic as it will work for any type, but I must warn you, that as with any reflection-based approach, it shouldn’t be overused, as it may cause performance issues.