Java 8: How to Write Lambda Stream to Work With Jsonarray

Java 8: How to write lambda stream to work with JsonArray?

JSONArray is a sub-class of java.util.ArrayList and JSONObject is a sub-class of java.util.HashMap.

Therefore, new JSONObject().put("name", "John") returns the previous value associated with the key (null), not the JSONObject instance. As a result, null is added to the JSONArray.

This, on the other hand, works:

    JSONArray jsonArray = new JSONArray();
JSONObject j1 = new JSONObject();
j1.put ("name", "John");
JSONObject j2 = new JSONObject();
j2.put ("name", "David");
jsonArray.add(j1);
jsonArray.add(j2);
Stream<String> ss = jsonArray.stream().map (json->json.toString ());
List<String> list = ss.collect (Collectors.toList ());
System.out.println(list);

For some reason I had to split the stream pipeline into two steps, because otherwise the compiler doesn't recognize that .collect (Collectors.toList()) returns a List.

The output is:

[{"name":"John"}, {"name":"David"}]

Java 8: Is there a batter way to filter JSONArray?

You could use IntStream with getBoolean:

JSONArray arr = new JSONArray();
arr.put(false);
arr.put(true);
arr.put(false);

//JSONArray is a list of objects
boolean b = IntStream.range(0, arr.length())
.anyMatch(arr::getBoolean);

System.out.println(b);

Output

true

As an alternative you could use the following:

boolean b = StreamSupport.stream(arr.spliterator(), false)
.anyMatch(Boolean.TRUE::equals);

The above solution does handle the JSONException problem, for instance it returns true for the following input:

JSONArray arr = new JSONArray();
arr.put(false);
arr.put(1);
arr.put(true);

Find JsonObject in JsonArray (javax.json.JsonArray) By Key or Value Using Java 8 Lambas

Solution

List<JsonValue> objects1 = answersArray.stream().filter(obj -> 
((JsonObject)obj).getString("extra") != null).collect(Collectors.toList());

List<JsonValue> objects2 = answersArray.stream().filter(obj ->
"SPECIAL".equals(((JsonObject)obj).getString("activityQuestionId")).collect(Collectors.toList());

JSONObject and Streams/Lambda

You can do like this:

first of all to extract data from JsonObject I've created a class. this class takes a JosonObject as an argument and extract its values as bellow.

class ExtractData {
Integer ip;
long id;
double amount;

public ExtractData(JSONObject jsonObject) {
this.ip = Integer.valueOf(jsonObject.get("ip").toString().split("\\.")[0]);
this.id = Long.parseLong(((JSONObject) jsonObject.get("location")).get("id").toString());
try {
this.amount = NumberFormat.getCurrencyInstance(Locale.US)
.parse((String) jsonObject.get("amount")).doubleValue();
} catch (ParseException e) {
this.amount = 0d;
}
}

// getter&setter
}

then you can use stream API to calculate the sum of the amount property.

jsonArray.stream()
.map(obj -> new ExtractData((JSONObject) obj))
.filter(predicate)
.mapToDouble(value -> ((ExtractData) value).getAmount())
.sum();

for simplifying I've extracted filter operation.

Predicate<ExtractData> predicate = extractData -> 
extractData.getIp()>=1 && extractData.getIp()<=100 && extractData.getId() == 8;

sorting a json array using java 8 stream api

Probably you are looking for code like this:

objectsArray.stream().sorted(
Comparator.comparing(a -> Double.valueOf((String)((JSONObject) a).get("distance")))
).forEach(o -> System.out.println(o));

The casts that we are using are the following:

((JSONObject) a).get("distance")) //to get the distance as an Object

and then

((String) ((JSONObject) a).get("distance"))) // this Object is actually a String, so cast to it

and then

Double.valueOf((String)((JSONObject) a).get("distance")) //this String, however, is a double, and we want to compare the double size, not alphabetically 

Cause you'd need to compare based on the double value of the distance.

However, there are multiple things to improve. As we are using OOP here, it probably makes sense to at least convert the "String" stream to some objects that'd make sense.

EDIT:

Here's how you probably should have done it:

//define a class to conform with OOP stuff
public static class Coordinate {

private final Double lat;
private final Double lon;
private final Integer type;
private final Double distance;

public Coordinate(Double lat, Double lon, Integer type, Double distance){
this.lat = lat;
this.lon = lon;
this.type = type;
this.distance = distance;
}

public Double getDistance() {
return distance;
}
}

// define a conversion logic
private static Coordinate convert(JSONObject raw){
Double distance = Double.valueOf((String) raw.get("distance"));
Double lon = Double.valueOf((String) raw.get("lon"));
Double lat = Double.valueOf((String) raw.get("lat"));
Integer type = Integer.valueOf((String) raw.get("type"));
return new Coordinate(lat, lon, type, distance);
}

then your method is as easy as writing:

List<JSONObject> coordinates = (List<JSONObject>)new JSONParser().parse(objects);
List<Coordinate> sortedCoordinates = coordinates
.stream()
.map(raw -> convert(raw))
.sorted(Comparator.comparing(Coordinate::getDistance))
.collect(Collectors.toList());

Another tip I have for you is using a better library like https://github.com/FasterXML/jackson for your object mapping.



Related Topics



Leave a reply



Submit