Java中JSON数据提取与处理

Java中JSON数据提取与处理的完整指南

引言

在开发中,JSON数据的处理已经成为日常任务。无论是与前端交互、调用第三方API,还是处理数据库中的JSON字段,我们需要解析和提取JSON数据。

1. 基础JSON数组解析

场景描述

处理简单的JSON数组字符串,将其转换为Java集合。

示例JSON

复制代码
["苹果", "香蕉", "橙子", ""]

处理方法

复制代码
public List<String> parseSimpleJsonArray(String jsonArrayStr) {
    List<String> resultList = new ArrayList<>();
    
    // 第一步:严格的空值检查
    if (jsonArrayStr == null || jsonArrayStr.trim().isEmpty()) {
        return resultList; // 返回空集合而不是null
    }
    
    try {
        // 第二步:JSON解析
        JSONArray jsonArray = JSONArray.parseArray(jsonArrayStr);
        
        // 第三步:遍历和数据处理
        for (int i = 0; i < jsonArray.size(); i++) {
            String item = jsonArray.getString(i);
            
            // 第四步:数据验证和清理
            if (item != null && !item.trim().isEmpty()) {
                resultList.add(item.trim());
            }
        }
    } catch (Exception e) {
        // 第五步:异常处理
        log.error("解析简单JSON数组失败,原始数据: {}", jsonArrayStr, e);
        // 根据业务需求决定是否抛出异常或返回空列表
    }
    
    return resultList;
}

关键要点

  • 防御性编程:始终进行null检查和空字符串检查

  • 数据清理:使用trim()去除空白字符

  • 异常恢复:在catch块中提供合理的默认返回值

2. 对象数组的特定字段提取

场景描述

从包含多个对象的JSON数组中提取特定字段的值。

示例JSON

复制代码
[
    {
        "id": 1,
        "username": "john_doe",
        "email": "john@example.com",
        "age": 25
    },
    {
        "id": 2,
        "username": "jane_smith",
        "email": "jane@example.com",
        "age": 30
    }
]

处理方法

复制代码
public List<String> extractSpecificFields(String jsonArrayStr, String... fieldNames) {
    List<String> extractedValues = new ArrayList<>();
    
    if (jsonArrayStr == null || jsonArrayStr.trim().isEmpty()) {
        return extractedValues;
    }
    
    try {
        JSONArray jsonArray = JSONArray.parseArray(jsonArrayStr);
        
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            
            // 提取指定的多个字段
            for (String fieldName : fieldNames) {
                if (jsonObject.containsKey(fieldName)) {
                    String value = jsonObject.getString(fieldName);
                    if (value != null && !value.trim().isEmpty()) {
                        extractedValues.add(value.trim());
                    }
                }
            }
        }
    } catch (Exception e) {
        log.error("提取字段失败,字段: {}, 数据: {}", 
                 Arrays.toString(fieldNames), jsonArrayStr, e);
    }
    
    return extractedValues;
}

// 使用示例
List<String> emails = extractSpecificFields(userJson, "email");
List<String> namesAndEmails = extractSpecificFields(userJson, "username", "email");

关键要点

  • 灵活性:通过可变参数支持多个字段的提取

  • 键存在性检查:使用containsKey()避免MissingKey异常

  • 批量处理:一次遍历处理多个字段,提高效率

3. 通用对象值提取方法

场景描述

提取JSON数组中所有对象的所有值,适用于不确定数据结构的情况。

示例JSON

复制代码
[
    {
        "firstName": "张",
        "lastName": "三",
        "department": "技术部"
    },
    {
        "employeeId": "E1002",
        "position": "工程师",
        "level": "P7"
    }
]

处理方法

复制代码
public List<String> extractAllValuesFromObjects(String jsonArrayStr) {
    List<String> allValues = new ArrayList<>();
    
    if (jsonArrayStr == null || jsonArrayStr.trim().isEmpty()) {
        return allValues;
    }
    
    try {
        JSONArray jsonArray = JSONArray.parseArray(jsonArrayStr);
        
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            
            // 遍历对象的所有键
            for (String key : jsonObject.keySet()) {
                try {
                    // 尝试以字符串形式获取值
                    String value = jsonObject.getString(key);
                    if (value != null && !value.trim().isEmpty()) {
                        allValues.add(value.trim());
                    }
                } catch (Exception e) {
                    // 处理非字符串值的情况
                    Object obj = jsonObject.get(key);
                    if (obj != null) {
                        allValues.add(obj.toString());
                    }
                }
            }
        }
    } catch (Exception e) {
        log.error("提取所有值失败,数据: {}", jsonArrayStr, e);
    }
    
    return allValues;
}

关键要点

  • 通用性:处理各种数据类型的值

  • 错误隔离:单个键值提取失败不影响其他值的处理

  • 类型安全:正确处理非字符串类型的值

4. 复杂嵌套结构处理

场景描述

处理多层嵌套的JSON结构,提取深层次的数据。

示例JSON

复制代码
{
    "company": {
        "name": "某科技有限公司",
        "departments": [
            {
                "name": "研发部",
                "employees": [
                    {
                        "id": 101,
                        "personalInfo": {
                            "name": "李四",
                            "contact": {
                                "email": "lisi@company.com",
                                "phone": "13800138000"
                            }
                        }
                    }
                ]
            }
        ]
    }
}

处理方法

复制代码
public List<String> extractFromNestedStructure(String complexJson) {
    List<String> results = new ArrayList<>();
    
    if (complexJson == null || complexJson.trim().isEmpty()) {
        return results;
    }
    
    try {
        JSONObject root = JSONObject.parseObject(complexJson);
        
        // 安全地访问嵌套属性
        JSONObject company = root.getJSONObject("company");
        if (company != null) {
            // 提取公司名称
            String companyName = company.getString("name");
            addIfNotEmpty(results, companyName);
            
            // 处理部门数组
            JSONArray departments = company.getJSONArray("departments");
            if (departments != null) {
                for (int i = 0; i < departments.size(); i++) {
                    JSONObject dept = departments.getJSONObject(i);
                    processDepartment(dept, results);
                }
            }
        }
    } catch (Exception e) {
        log.error("解析嵌套JSON结构失败", e);
    }
    
    return results;
}

private void processDepartment(JSONObject department, List<String> results) {
    String deptName = department.getString("name");
    addIfNotEmpty(results, deptName);
    
    JSONArray employees = department.getJSONArray("employees");
    if (employees != null) {
        for (int i = 0; i < employees.size(); i++) {
            JSONObject employee = employees.getJSONObject(i);
            processEmployee(employee, results);
        }
    }
}

private void processEmployee(JSONObject employee, List<String> results) {
    JSONObject personalInfo = employee.getJSONObject("personalInfo");
    if (personalInfo != null) {
        String name = personalInfo.getString("name");
        addIfNotEmpty(results, name);
        
        JSONObject contact = personalInfo.getJSONObject("contact");
        if (contact != null) {
            String email = contact.getString("email");
            String phone = contact.getString("phone");
            addIfNotEmpty(results, email);
            addIfNotEmpty(results, phone);
        }
    }
}

private void addIfNotEmpty(List<String> list, String value) {
    if (value != null && !value.trim().isEmpty()) {
        list.add(value.trim());
    }
}

关键要点

  • 模块化:将复杂逻辑分解为小方法

  • 安全访问:逐层检查JSONObject是否为null

  • 关注点分离:每个方法只负责一个层级的处理

5. 高级技巧和最佳实践(AI)

5.1 使用Optional避免空指针

复制代码
public Optional<List<String>> safeJsonExtraction(String jsonStr) {
    return Optional.ofNullable(jsonStr)
        .filter(str -> !str.trim().isEmpty())
        .map(str -> {
            try {
                return JSONArray.parseArray(str);
            } catch (Exception e) {
                log.warn("JSON解析警告", e);
                return null;
            }
        })
        .map(this::extractValuesSafely)
        .orElse(Optional.empty());
}

5.2 性能优化-批量处理

复制代码
public <T> List<T> batchProcessJson(List<String> jsonList, 
                                   Function<String, List<T>> processor) {
    return jsonList.parallelStream()
        .map(processor)
        .flatMap(List::stream)
        .collect(Collectors.toList());
}

5.3 自定义异常处理

复制代码
public class JsonProcessingException extends RuntimeException {
    private final String originalJson;
    
    public JsonProcessingException(String message, String originalJson, Throwable cause) {
        super(message, cause);
        this.originalJson = originalJson;
    }
    
    // 提供更友好的错误信息
    public String getUserMessage() {
        return "数据处理失败,请检查数据格式";
    }
}

6. 完整的工具类示例

复制代码
@Slf4j
public class JsonExtractionUtils {
    
    private JsonExtractionUtils() {
        // 工具类,防止实例化
    }
    
    /**
     * 通用JSON数组值提取器
     */
    public static List<String> extractValues(String jsonArrayStr, 
                                           ValueExtractor... extractors) {
        List<String> results = new ArrayList<>();
        
        if (!isValidJsonString(jsonArrayStr)) {
            return results;
        }
        
        try {
            JSONArray jsonArray = JSONArray.parseArray(jsonArrayStr);
            for (int i = 0; i < jsonArray.size(); i++) {
                Object item = jsonArray.get(i);
                processJsonItem(item, extractors, results);
            }
        } catch (Exception e) {
            handleJsonException("JSON数组解析失败", jsonArrayStr, e);
        }
        
        return results;
    }
    
    private static boolean isValidJsonString(String jsonStr) {
        return jsonStr != null && !jsonStr.trim().isEmpty();
    }
    
    private static void processJsonItem(Object item, 
                                      ValueExtractor[] extractors, 
                                      List<String> results) {
        if (item instanceof JSONObject) {
            processJsonObject((JSONObject) item, extractors, results);
        } else if (item instanceof String) {
            processStringValue((String) item, results);
        }
        // 可以扩展处理其他类型
    }
    
    private static void processJsonObject(JSONObject jsonObject, 
                                        ValueExtractor[] extractors, 
                                        List<String> results) {
        for (ValueExtractor extractor : extractors) {
            try {
                extractor.extract(jsonObject, results);
            } catch (Exception e) {
                log.warn("字段提取失败: {}", extractor.getFieldName(), e);
            }
        }
    }
    
    private static void processStringValue(String value, List<String> results) {
        if (value != null && !value.trim().isEmpty()) {
            results.add(value.trim());
        }
    }
    
    private static void handleJsonException(String message, 
                                          String jsonStr, 
                                          Exception e) {
        log.error("{}: {}", message, jsonStr, e);
        // 根据环境决定是否抛出异常
        if (isProduction()) {
            throw new JsonProcessingException(message, jsonStr, e);
        }
    }
    
    private static boolean isProduction() {
        return "prod".equals(System.getProperty("app.env"));
    }
    
    @FunctionalInterface
    public interface ValueExtractor {
        void extract(JSONObject jsonObject, List<String> results);
        default String getFieldName() { return "unknown"; }
    }
}

总结

在处理JSON数据时,记住以下核心原则:

  1. 安全性优先:始终进行空值检查和异常处理

  2. 数据验证:验证提取数据的有效性和完整性

  3. 代码可读性:使用清晰的命名和模块化设计

  4. 性能考虑:对于大数据量考虑使用流式处理

  5. 可维护性:提供清晰的错误信息和日志记录

通过遵循这些模式和最佳实践,你可以构建出健壮、可维护的JSON处理代码,轻松应对各种复杂的数据提取场景。

相关推荐
Han.miracle6 小时前
Java的多线程——多线程(二)
java·开发语言·线程·多线程
没有bug.的程序员6 小时前
Spring Boot 整合第三方组件:Redis、MyBatis、Kafka 实战
java·spring boot·redis·后端·spring·bean·mybatis
cherryc_7 小时前
JavaSE基础——第十二章 集合
java·开发语言
wgb04097 小时前
vxe table 升级之后页面数据不显示解决方法
java·前端·javascript
May’sJL7 小时前
Redis高可用-主从复制
java·redis·缓存
无敌最俊朗@7 小时前
SQlite:电影院售票系统中的主键(单列,复合)约束应用
java·开发语言·数据库
行思理7 小时前
macos 如何清空IntelliJ IDEA安装记录
java·macos·intellij-idea
信码由缰7 小时前
Java 运行时安全:输入验证、沙箱机制、安全反序列化
java
Dying.Light8 小时前
Java基础复习-中-集合
java