Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - getting a list of new objects from a stream based on the list of the existing ones

I need to use lambdas to generate some lists of new objects. These new objects inherit some of the traits from the existing ones. Since it's hard to describe it without going into too much delicate details, I'll use an example of a parent and their children.

I want to generate a list of kids based on a list of people (one person = one kid). Kids should inherit only some traits of their parents (in this case, let's say it's a skin colour).

Since I'm somewhat forced to use lambdas (but also want to learn how it works), I've tried the following solution but I can't get over the problem with correct mapping (haven't seen anything like that yet and I'm doing a trial&error method). Probably I have a badly made constructor as well.

public class Kid {
    private Colour colour;
    private Person person;

    public Kid(Person person) {
        this.colour = person.getColour();
    }

    public List<Kid> listOfKids() {
        return people.stream()
                     .map(e -> new Kid(e));
    }
}
like image 891
DrAhzek Avatar asked Dec 23 '18 01:12

DrAhzek


2 Answers

After map you have a Stream<Kid> rather what you need is a List<Kid> thus you'll need to collect to a list via toList().

return people.stream()
             .map(e -> new Kid(e))
             .collect(Collectors.toList());

or if you need a mutable list then use toCollection:

return people.stream()
             .map(e -> new Kid(e))
             .collect(Collectors.toCollection(ArrayList::new));

On another note, you'll need to rethink your design.

  1. instead of passing a whole Person to the Kid constructor just pass a Colour (assuming it's an enum) otherwise pass String to represent the colour.
  2. having a Person attribute inside a Kid model doesn't make much sense to be honest, it's like saying "a kid has a person"... maybe what you're looking for is a Kid to inherit from Person to indicate that "a kid is a person"

etc...

like image 171
Ousmane D. Avatar answered Oct 19 '22 11:10

Ousmane D.


Alternatively, you can use method reference in map as:

public List<Kid> listOfKids(List<Person> people) {
    return people.stream()
                 .map(Kid::new) // your existing constructor resolves this
                 .collect(Collectors.toList());
}

Do, note that though the constructor implementation though compiles fine, if you want to keep Person and Colour as attributes of class Kid it would make more sense with something like:

// assign both attributes of the class within your constructor
public Kid(Person person, Colour colour) {
    this.person = person;
    this.colour = colour;
}

and then updating the mapping function as:

public List<Kid> listOfKids(List<Person> people) {
    return people.stream()
                 .map(p -> new Kid(p, p.getColour())) // map to the updated contructor
                 .collect(Collectors.toList());
}

Kids should inherit only some traits of their parents (in this case, let's say it's a skin colour).

In which case you can use inheritance in java by extending your class Kid from Person class, for which all you would need is

public class Kid extends Person {
     public Kid(Colour colour) {
         super(colour);
     }
}

where class Person definition could be something like:

public class Person {
    Colour colour;
    public Person(Colour colour) {
        this.colour = colour;
    }
}

then with this change, your method would look like

public List<Kid> listOfKids(List<Person> people) {
    return people.stream()
                 .map(p -> new Kid(p.getColour()))
                 .collect(Collectors.toList());
}
like image 34
Naman Avatar answered Oct 19 '22 11:10

Naman