If you want to iterate over a list and create a new list with "transformed" objects, you should use the map() function of stream + collect(). In the following example I find all people with the last name "l1" and each person I'm "mapping" to a new Employee instance.
public class Test {
public static void main(String[] args) {
List<Person> persons = Arrays.asList(
new Person("e1", "l1"),
new Person("e2", "l1"),
new Person("e3", "l2"),
new Person("e4", "l2")
);
List<Employee> employees = persons.stream()
.filter(p -> p.getLastName().equals("l1"))
.map(p -> new Employee(p.getName(), p.getLastName(), 1000))
.collect(Collectors.toList());
System.out.println(employees);
}
}
class Person {
private String name;
private String lastName;
public Person(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
// Getter & Setter
}
class Employee extends Person {
private double salary;
public Employee(String name, String lastName, double salary) {
super(name, lastName);
this.salary = salary;
}
// Getter & Setter
}
Answer from Rafael Teles on Stack OverflowIf you want to iterate over a list and create a new list with "transformed" objects, you should use the map() function of stream + collect(). In the following example I find all people with the last name "l1" and each person I'm "mapping" to a new Employee instance.
public class Test {
public static void main(String[] args) {
List<Person> persons = Arrays.asList(
new Person("e1", "l1"),
new Person("e2", "l1"),
new Person("e3", "l2"),
new Person("e4", "l2")
);
List<Employee> employees = persons.stream()
.filter(p -> p.getLastName().equals("l1"))
.map(p -> new Employee(p.getName(), p.getLastName(), 1000))
.collect(Collectors.toList());
System.out.println(employees);
}
}
class Person {
private String name;
private String lastName;
public Person(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
// Getter & Setter
}
class Employee extends Person {
private double salary;
public Employee(String name, String lastName, double salary) {
super(name, lastName);
this.salary = salary;
}
// Getter & Setter
}
What you are possibly looking for is map(). You can "convert" the objects in a stream to another by mapping this way:
...
.map(userMeal -> new UserMealExceed(...))
...
collections - How can I turn a List of Lists into a List in Java 8? - Stack Overflow
To get list of member from list of objects using Streams java - Stack Overflow
lambda - Retrieving a List from a java.util.stream.Stream in Java 8 - Stack Overflow
Proposal for stream: a (casting) filter by class
Videos
Use flatMap:
List<Integer> concat = examples.stream()
.flatMap(e -> e.getIds().stream())
.collect(Collectors.toList());
Another solution by using method reference expression instead of lambda expression:
List<Integer> concat = examples.stream()
.map(Example::getIds)
.flatMap(List::stream)
.collect(Collectors.toList());
You can use flatMap to flatten the internal lists (after converting them to Streams) into a single Stream, and then collect the result into a list:
List<List<Object>> list = ...
List<Object> flat =
list.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
The flatMap method on Stream can certainly flatten those lists for you, but it must create Stream objects for element, then a Stream for the result.
You don't need all those Stream objects. Here is the simple, concise code to perform the task.
// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);
Because a List is Iterable, this code calls the forEach method (Java 8 feature), which is inherited from Iterable.
Performs the given action for each element of the
Iterableuntil all elements have been processed or the action throws an exception. Actions are performed in the order of iteration, if that order is specified.
And a List's Iterator returns items in sequential order.
For the Consumer, this code passes in a method reference (Java 8 feature) to the pre-Java 8 method List.addAll to add the inner list elements sequentially.
Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator (optional operation).
What you are doing may be the simplest way, provided your stream stays sequential—otherwise you will have to put a call to sequential() before forEach.
The reason the call to sequential() is necessary is that the code as it stands (forEach(targetLongList::add)) would be racy if the stream was parallel. Even then, it will not achieve the effect intended, as forEach is explicitly nondeterministic—even in a sequential stream the order of element processing is not guaranteed. You would have to use forEachOrdered to ensure correct ordering. The intention of the Stream API designers is that you will use collector in this situation, as below:
targetLongList = sourceLongList.stream()
.filter(l -> l > 100)
.collect(Collectors.toList());
One approach is to use Collectors.toList to collect the stream into a list:
targetLongList =
sourceLongList.stream().
filter(l -> l > 100).
collect(Collectors.toList());
If a specific List implementation is desired, Collectors.toCollection can be used instead:
targetLongList =
sourceLongList.stream().
filter(l -> l > 100).
collect(Collectors.toCollection(ArrayList::new));