10

Im having a double array , I need to convert the array into a JSONArray using java streams. I tried using forEach (shared mutability) which leads to loss of data.

public static JSONArray arrayToJson(double[] array) throws JSONException{
    JSONArray jsonArray = new JSONArray();
    
    Arrays.stream(array)
         .forEach(jsonArray::put);  

    return jsonArray;
}

Is there any way I could to create JSONArray using streams?

7
  • What do you mean by "loss of data"? Commented Jan 8, 2018 at 6:50
  • Your code works fine and no data lost. Commented Jan 8, 2018 at 6:52
  • 2
    what JSon library you are using! Commented Jan 8, 2018 at 6:54
  • 2
    why you use parallel stream, for what purpose ? and please edit your question and add this information, it's can make different. Commented Jan 8, 2018 at 7:18
  • 2
    JSONArray is not thread safe, you can see the documents. Commented Jan 8, 2018 at 7:52

2 Answers 2

20

Your code works, but you can write something like this (jdk 8+):

return Arrays.stream(array)
             .collect(Collector.of(
                          JSONArray::new, //init accumulator
                          JSONArray::put, //processing each element
                          JSONArray::put  //confluence 2 accumulators in parallel execution
                     ));

one more example (create a String from List<String>):

List<String> list = ...
String str = list.stream()
                 .collect(Collector.of(
                    StringBuilder::new,
                    StringBuilder::append,
                    StringBuilder::append,
                    StringBuilder::toString //last action of the accumulator (optional)  
                 ));

Looks nice, but compiler complaints: error: incompatible thrown types JSONException in method reference .collect(Collector.of(JSONArray::new, JSONArray::put, JSONArray::put)

I checked this on jdk 13.0.1 and JSON 20190722 and didn't find problems except of Expected 3 arguments, but found 1 in .collect(...).

(Gradle : implementation group: 'org.json', name: 'json', version: '20190722')


Fix:

public static JSONArray arrayToJson(double[] array) throws JSONException {
    return Arrays.stream(array).collect(
            JSONArray::new,
            JSONArray::put,
            (ja1, ja2) -> {
                for (final Object o : ja2) {
                    ja1.put(o);
                }
            }
    );
}

Note: The combiner cannot be a method reference to just JSONArray::put because this will just put one array into the other (e.g. [[]]) instead of actually combining them as is the desired behavior.

Sign up to request clarification or add additional context in comments.

1 Comment

Looks nice, but compiler complaints: error: incompatible thrown types JSONException in method reference .collect(Collector.of(JSONArray::new, JSONArray::put, JSONArray::put))
3

JSONArray is not thread safe. If you are using parallel stream you should synchronize the operation.

Arrays
    .stream(array)
    .parallel()
    .forEach(e -> {
        synchronized(jsonArray) {
            jsonArray.put(e);
        }
    });

1 Comment

If you synchronize the operation, you don't need to use parallel, as you do not have any advantage of it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.