Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a List to a constructor of a new object using java lambda expression?

I have a problem where I want to convert a list of POJOs into DTOs and pass them into a wrapper object which is then returned. Consider this working piece of code:

List<Device> devices = dbService.getDevices(...);
List<DeviceDTO> devicesDTO = new ArrayList<DeviceDTO>();
for (Device d : devices) {
   devicesDTO.add(convertToDTO(d));
}

WrapperDTO wrapper = new WrapperDTO(devicesDTO);

I am looking for a way to rewrite this into smaller, maybe more elegant, piece of code using Java lambda expressions. This is what I have done so far. I can do the conversion from POJOs to DTOs but I am struggling to pass the list of DTOs to the constructor of a new wrapper object.

List<Device> devices = dbService.getDevices(...);
List<DeviceDTO> devicesDTO = devices.stream().map(d -> convertToDTO(d)).collect(Collectors.toList());

WrapperDTO wrapper = new WrapperDTO(devicesDTO);

How could I get it even shorter a one-liner, something like this?

WrapperDTO wrapper = devices.stream()........collect( () -> WrapperDTO:new);

Obviously, the last piece is not working but that is something I would like to achieve. Any suggestions? Thank you my friends:)

like image 501
user3732445 Avatar asked Jan 11 '20 11:01

user3732445


People also ask

How do you pass a lambda expression as a method parameter in Java?

Passing Lambda Expressions as Arguments If you pass an integer as an argument to a function, you must have an int or Integer parameter. If you are passing an instance of a class as a parameter, you must specify the class name or the object class as a parameter to hold the object.

Can a lambda expression be assigned to an object variable?

If you assign a lambda expression to a variable of type Object , the compiler has no idea which functional interface this lambda expression should implement. For example, the lambda expression o -> o. toString () can be assigned to either a Consumer or a Function : Consumer<String> cons = o -> o.

Which method you can pass lambda expression?

If we need to pass a lambda expression as an argument, the type of parameter receiving the lambda expression argument must be of a functional interface type. In the below example, the lambda expression can be passed in a method which argument's type is "TestInterface".


2 Answers

You may use collectingAndThen collector to solve it in one fell swoop. Use the toList collector as the downstream collector and pass the WrapperDTO::new constructor reference as the finisher function. Here's how it looks.

final WrapperDTO wrapper = devices.stream()
    .map(d -> convertToDTO(d))
    .collect(Collectors.collectingAndThen(Collectors.toList(), WrapperDTO::new));
like image 173
Ravindra Ranwala Avatar answered Oct 13 '22 01:10

Ravindra Ranwala


There is a naughty secret: write a map function for List.

Stash that little one away, and then all you need is:

WrapperDTO wrapper = new WrapperDTO(map(devices, MyClass::convertToDTO));

Don't tell the streams cool kids.

map for List should look something like:

public static <T, R> List<R> map​(
    List<T> source, Function<? super T,​? extends R> mapper
) {
    List<R> result = new ArrayList<>();
    for (T item : source) {
        result.add(mapper.apply(item));
    }
    return result;
}
like image 35
Tom Hawtin - tackline Avatar answered Oct 13 '22 01:10

Tom Hawtin - tackline