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
How to Check Type of Variable in Java
Java Classes to Generate the Given Json String
Intellij Incorrectly Saying No Beans of Type Found for Autowired Repository
How to Check If a Date Is Within a Certain Range
How to Check If an Int Is a Null
Java Spring: Best Way to Convert a File to a Multipartfile
How to Prevent Duplicate Results in Hibernate
How to Set a Timeout on a Spring Boot Rest API
How to Use Variables in One Method into Another Method
How to Bypass Google Recaptcha for Testing Using Selenium
How to Upload a File and Json Data in Postman
How to Determine If a List of String Contains Null or Empty Elements
How to Pass JavaScript Values to Scriptlet in Jsp
How to Print Out All the Elements of a List in Java
Remove Duplicates from a List of Objects Based on Property in Java 8
How to Fill Hashmap from Java Property File With Spring @Value