Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would you do multiple operations on a java 8 stream?

You have a list of a pojo you want to convert to a JSONObject for instance. You have a list of pojo. But in order to convert to a JSONObject you need to use the JSONObject put method.

JSONObject personJson = new JSONObject();
for(Person person : personList){
   personJson.put("firstName", person.firstName);
   personJson.put("lastName", person.lastname);
   ...
}

If it were just one operation I wanted to do, then I could do

personList.stream.map(personJson.put("firstName", person.firstName));
like image 644
obesechicken13 Avatar asked Feb 21 '17 06:02

obesechicken13


People also ask

How do you do multiple operations on a stream?

The correct approach would be to use . map() which, like the name says, maps one value to another. In your case the first operation you want to do is to map a Person to a JSONObject. The second operation is a reducer function where you want to reduce all JSONObjects to one JSONArray object.

Can stream pipeline have multiple terminal operations?

No. You cannot use a stream multiple times.

How many types of operations can we perform on stream?

There are two types of operations in streams, some operations produce another stream as a result and some operations produce non-stream values as a result. So we can say that stream interface has a selection of terminal and non-terminal operations.

Can we use multiple filter in stream?

2.1. Multiple Filters. The Stream API allows chaining multiple filters.


2 Answers

 JSONArray array=new JSONArray();
        personList.stream().forEach(element ->
        {
            JSONObject personJson = new JSONObject();
            personJson.put("firstName", element.firstName);
            personJson.put("lastName", element.lastname);
            array.add(personJson);
        });
like image 142
Karthik Bharadwaj Avatar answered Sep 28 '22 12:09

Karthik Bharadwaj


The solutions mentioned here are working but they are mutating objects outside the streams context, which should be avoided.

So instead of using .forEach() which is a terminating operation returning void. The correct approach would be to use .map() which, like the name says, maps one value to another. In your case the first operation you want to do is to map a Person to a JSONObject. The second operation is a reducer function where you want to reduce all JSONObjects to one JSONArray object.

public JSONArray mapListToJsonArray(List<Person> persons) {
    List<JSONObject> jsonObjects = persons
            .stream()
            .map(person -> {
                JSONObject json = new JSONObject();
                json.put("firstName", person.getFirstName());
                json.put("lastName", person.getLastName());
                return json;
            })
            .collect(Collectors.toList());
    return new JSONArray(jsonObjects);
}

Unfortunately the json.org implementation of JSONArray does not have a way to easily merge two arrays. So I instead of reducing to a JSONArray, I first collected all JSONObjects as a List and created a JSONArray from that.

The solution looks even nicer if you replace the lambda expression with a method reference.

public JSONArray mapListToJsonArray(List<Person> persons) {
    List<JSONObject> jsonObjects = persons
            .stream()
            .map(this::mapPersonToJsonObject)
            .collect(Collectors.toList());
    return new JSONArray(jsonObjects);
}

public JSONObject mapPersonToJsonObject(Person person) {
    JSONObject json = new JSONObject();
    json.put("firstName", person.getFirstName());
    json.put("lastName", person.getLastName());
    return json;
}
like image 40
Marvin Richter Avatar answered Sep 28 '22 10:09

Marvin Richter