sicio
sicio

Reputation: 307

Java lambda stream merge parameters in model

I cant find answer. I try to merge multiple Object to one. Example model

public class Model {
    private List<Map<String, Object>> param1;
    private List<String> param2;
}

In my code, I convert another data to model.

List<Model> models = models2.stream()
    .map(Optional::get)
    .map(model2 -> convert(model2))
    .collect(Collectors.toList()); 

I try to aggregate converted list of models to one Model. Like:

Model model = models2.stream() ...etc

but I dont know how.

Upvotes: 0

Views: 381

Answers (2)

ETO
ETO

Reputation: 7279

First of all your current code contains a hidden unobvious bug. The operation Optional::get will throw an exception when an empty Optional met. You should filter out the empty optionals first:

// ...
.filter(Optional::isPresent)
.map(Optional::get)
// ...

Or if you're using java-9 or above you can simply flat-map the optional values:

// ...
.flatmap(Optional::stream)
// ...   

As for your question, it looks like you need to reduce with a merge-function. There are different ways to define that function:

  1. Method reference:

    private Model merge(Model model1, Model model2) {
        // merge model2 to model1
        return model1;
    }
    
    Model model = models2.stream()
            .filter(Optional::isPresent)
            .map(Optional::get)
            .map(this::convert)
            .reduce(this::merge)
            .orElse(defaultModel);
    
  2. A BinaryOperator stored in a variable:

    BinaryOperator<Model> merge = (model1, model2) -> { /* do smth */; return model1;}  
    
    // ... 
    .map(this::convert)
    .reduce(merge)
    //
    
  3. Inline lambda

    // ... 
    .map(this::convert)
    .reduce((model1, model2) -> { /* do smth */; return model1;})
    //
    

IMHO the first option is the best one. Having a separate method will make your code cleaner and easier to maintain.

Upvotes: 0

ernest_k
ernest_k

Reputation: 45319

The easiest is to add a merge method to your Model class:

public class Model {
    private List<HashMap<String, Object>> param1;
    private List<String> param2;

    public Model merge (Model other) {
        this.param1.addAll(other.param1);
        this.param2.addAll(other.param2);

        return this;
    }
}

And then reduce your stream:

Model allInOne = models2.stream()
    .map(Optional::get)
    .map(model2 -> convert(model2))
    .reduce(Model::merge)
    .get();

That merge method can also be a static Model merge (Model first, Model second) or externalized BinaryOperator<Model> function.

Upvotes: 1

Related Questions