Java中2种JSON对象排序方法

JSON是一种广泛使用的结构化数据格式,通常用于大多数现代 API 和数据服务。由于其轻量级特性和与 JavaScript 的兼容性,它在 Web 应用程序中特别受欢迎。

有时,在获取 JSON 的应用程序中显示数据之前对数据进行排序可能会很有用。

在本快速教程中,我们将看到2种在 Java 中对 JSON 对象进行排序的方法。

让我们首先定义一个相对简单的 JSON 结构,该结构模拟一些假想的太阳事件:

{
    "solar_events": [
        {
           
"event_name": "Solar Eclipse",
           
"date": "2024-04-08",
           
"coordinates": {
               
"latitude": 37.7749,
               
"longitude": -122.4194
            },
           
"size": "Large",
           
"speed_km_per_s": 1000
        },
        {
           
"event_name": "Solar Flare",
           
"date": "2023-10-28",
           
"coordinates": {
               
"latitude": 0,
               
"longitude": 0
            },
           
"size": "Small",
           
"speed_km_per_s": 100
        },
        {
           
"event_name": "Sunspot",
           
"date": "2023-11-15",
           
"coordinates": {
               
"latitude": 15,
               
"longitude": -75
            },
           
"size": "Large",
           
"speed_km_per_s": 1500
        },
        {
           
"event_name": "Coronal Mass Ejection",
           
"date": "2024-01-10",
           
"coordinates": {
               
"latitude": -5,
               
"longitude": 80
            },
           
"size": "Medium",
           
"speed_km_per_s": 500
        }
    ]
}

在本教程的整个过程中,此 JSON 文档将是我们的示例的重点。

1、使用 Jackson
在第一个例子中,我们将了解Jackson,一个用于处理 JSON 数据的多用途 Java 库。

首先,我们需要将jackson-databind依赖项添加到我们的pom.xml中:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.2</version>
</dependency>

我们还需要定义一些简单的 POJO 对象,用于将 JSON 字符串反序列化为 Java 对象:

class SolarEvent {
    @JsonProperty("event_name")
    private String eventName;
    @JsonProperty(
"date")
    private String date;
    @JsonProperty(
"coordinates")
    private Coordinates coordinates;
    @JsonProperty(
"type")
    private String type;
    @JsonProperty(
"class")
    private String eventClass;
    @JsonProperty(
"size")
    private String size;
    @JsonProperty(
"speed_km_per_s")
    private int speedKmPerS;
   
// Getters and Setters
}
class Coordinates {
    @JsonProperty(
"latitude")
    private double latitude;
    @JsonProperty(
"longitude")
    private double longitude;
   
// Getters and setters
}

我们还将定义一个容器对象来保存我们的事件列表:

class SolarEventContainer {
    @JsonProperty("solar_events")
    private List<SolarEvent> solarEvents;
   
//Getters and setters
}

现在,我们可以继续编写一个简单的单元测试来验证我们可以使用给定的属性对太阳事件列表进行排序:

@Test
void givenJsonObjects_whenUsingJackson_thenSortedBySpeedCorrectly() throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    SolarEventContainer container =
      objectMapper.readValue(new File("src/test/resources/solar_events.json"),
      SolarEventContainer.class);
    List<SolarEvent> events = container.getSolarEvents();
    Collections.sort(events, Comparator.comparingInt(event -> event.getSpeedKmPerS()));
    assertEquals(100, events.get(0).getSpeedKmPerS());
    assertEquals(500, events.get(1).getSpeedKmPerS());
    assertEquals(1000, events.get(2).getSpeedKmPerS());
    assertEquals(1500, events.get(3).getSpeedKmPerS());
}

我们的第一个目标是解析 JSON 并将其反序列化为我们的对象模型。为此,我们使用了 Jackson 的标准ObjectMapper。我们使用readValue()方法从文件中读取 JSON 并将 JSON 转换为SolarEventContainer对象。

现在我们有了 Java 对象模型,我们可以继续根据类中的任何属性对对象进行排序。对于排序,我们使用 lambda 表达式定义一个Comparator ,并使用compareInt()静态工厂使用getSpeedKmPerS()方法对事件进行排序 。

最后,我们的测试证实了速度属性正确地对事件进行了排序。

2、使用 Gson
现在,让我们看一下使用另一个流行的 JSON 处理库Gson 的类似方法。与前面一样,我们首先将此依赖项添加到pom.xml中:


    com.google.code.gson
    gson
    2.11.0

与往常一样,最新版本可从Maven 存储库获取。

有时,我们可能无法总是使用自己的内部 Java 对象模型,因此在此示例中,我们将看到如何使用可直接从此库获取的 JSON Java 对象:

@Test
public void givenJsonObject_whenUsingGson_thenSortedBySizeCorrectly() throws FileNotFoundException {
    JsonReader reader = new JsonReader(new FileReader("src/test/resources/solar_events.json"));
    JsonElement element = JsonParser.parseReader(reader);
    JsonArray events = element.getAsJsonObject().getAsJsonArray(
"solar_events");
    List<JsonElement> list = events.asList();
    Collections.sort(list, (a, b) -> {
        double latA = a.getAsJsonObject()
          .getAsJsonObject(
"coordinates")
          .get(
"latitude")
          .getAsDouble();
        double latB = b.getAsJsonObject()
          .getAsJsonObject(
"coordinates")
          .get(
"latitude")
          .getAsDouble();
        return Double.compare(latA, latB);
    });
    assertEquals(-5, getJsonAttributeAsInt(list.get(0)));
    assertEquals(0, getJsonAttributeAsInt(list.get(1)));
    assertEquals(15, getJsonAttributeAsInt(list.get(2)));
    assertEquals(37, getJsonAttributeAsInt(list.get(3)));
}
private int getJsonAttributeAsInt(JsonElement element) {
    return element.getAsJsonObject()
      .getAsJsonObject(
"coordinates")
      .get(
"latitude")
      .getAsInt();
}

如我们所见,我们使用类似的方法来读取示例 JSON 文件,但这一次,我们检索JsonElement对象列表,它代表我们的solar_events.json文件中的每个条目。

同样,我们现在可以使用Collections.sort方法对列表中的元素进行排序,方法是提供自定义比较器来解析并从 JSON 对象中选择所需的值。这当然比前面的示例更冗长一些,如​​果我们的 JSON 结构发生变化或我们输入了错误的 JSON 对象或属性名称,则容易出错。

最后,这一次,我们使用纬度值检查元素是否已正确排序。我们还提供了一个小的实用方法来帮助我们从 JSON 元素中提取值。