JSONObject 使用文档(Java/Android原生)

本文针对 Java/Android 原生 org.json.JSONObject 类,详细说明其常用方法、核心区别及避坑要点,适用于日常JSON解析场景,帮助开发者规避常见异常,提升解析安全性和效率。

适用场景:后端接口返回JSON数据解析、本地JSON数据构造与解析;不适用于第三方JSON解析框架(如Gson、FastJson)。

1. 介绍

JSONObject 是原生JSON解析的核心类,用于封装JSON对象(键值对集合),提供了一系列方法用于获取、设置、判断JSON中的键值对,核心分为「严格模式方法」和「容错模式方法」,对应 getXXX 系列和 optXXX 系列。

  • 引入依赖
xml 复制代码
	<dependency>
	    <groupId>org.json</groupId>
	    <artifactId>json</artifactId>
	    <version>20200518</version>
	</dependency>

2. 常用方法详解

2.1 构造方法

用于创建JSONObject实例,常用2种方式:

java 复制代码
// 1. 空构造,后续手动添加键值对
JSONObject json = new JSONObject();

// 2. 传入JSON字符串构造(最常用,注意字符串格式必须合法)
String jsonStr = "{\"msgid\":\"123456\",\"name\":\"测试\"}";
JSONObject json = new JSONObject(jsonStr); // 格式错误会抛JSONException

2.2 核心方法:getXXX 系列(严格模式)

核心特点:键(key)不存在、键对应值为null,或值类型不匹配时,直接抛出 JSONException,适用于「必填字段」的解析,强制校验数据完整性。

方法 功能 使用示例 异常场景
getString(String key) 获取指定key的字符串值 json.getString("msgid"); key不存在、值为null、值不是字符串
getInt(String key) 获取指定key的int值 json.getInt("age"); key不存在、值为null、值不是数字(含字符串数字)
getLong(String key) 获取指定key的long值 json.getLong("id"); 同getInt,额外注意值超过int范围
getBoolean(String key) 获取指定key的boolean值 json.getBoolean("flag"); key不存在、值为null、值不是boolean(含字符串"true"/"false")
getJSONObject(String key) 获取指定key的JSONObject子对象 json.getJSONObject("user"); key不存在、值为null、值不是JSONObject
getJSONArray(String key) 获取指定key的JSONArray数组 json.getJSONArray("list"); key不存在、值为null、值不是JSONArray

2.3 核心方法:optXXX 系列(容错模式)

核心特点:键不存在、值为null时,不抛异常,返回对应类型的默认值;值类型不匹配时,返回默认值(部分场景除外),适用于「非必填字段」的解析,提升程序稳定性。

所有optXXX方法均有重载版本,可自定义默认值(推荐使用,比无参版更安全)。

方法 无参默认值 重载方法(自定义默认值) 使用示例 注意点
optString(String key) ""(空字符串) optString(String key, String defaultValue) optString("name", "未知") 值为null时返回默认值,无异常
optInt(String key) 0 optInt(String key, int defaultValue) optInt("age", -1) 值为字符串数字(如"123")时,返回0(坑点)
optLong(String key) 0L optLong(String key, long defaultValue) optLong("id", 0L) 避免用于超长数字解析(如雪花ID),建议先转字符串
optBoolean(String key) false optBoolean(String key, boolean defaultValue) optBoolean("flag", false) 值为字符串"true"/"false"时,返回false(大坑)
optJSONObject(String key) null optJSONObject(String key, JSONObject defaultValue) optJSONObject("user", new JSONObject()) 返回null时,需手动判空,避免空指针
optJSONArray(String key) null optJSONArray(String key, JSONArray defaultValue) optJSONArray("list", new JSONArray()) 返回null时,需手动判空,避免空指针

2.4 辅助判断方法(高频使用)

用于判断键的存在性和值的有效性,避免盲目调用getXXX/optXXX方法,减少异常。

方法 功能说明 示例(JSON:{"a":null,"b":123}) 返回结果
has(String key) 判断key是否存在(无论值是否为null) json.has("a")、json.has("c") true、false
isNull(String key) 判断key不存在,或key存在但值为null json.isNull("a")、json.isNull("c") true、true
length() 获取JSON对象中键值对的数量 json.length() 2
keys() 获取所有key的迭代器 json.keys(); 迭代器包含"a"、"b"

2.5 其他常用方法

java 复制代码
// 1. 向JSON对象添加键值对
json.put("key", "value"); // 支持String、int、boolean等多种类型

// 2. 删除指定key
json.remove("key");

// 3. 将JSON对象转为字符串(格式化/非格式化)
String jsonStr = json.toString(); // 非格式化
String prettyJson = json.toString(4); // 格式化,缩进4个空格

// 4. 获取所有值的集合
JSONArray values = json.toJSONArray(json.keys());

3. 常见坑点及避坑指南(重点)

3.1 数字解析坑(高频踩雷)

后端返回字符串数字(如{"age":"18"})时,getInt/optInt会抛异常或返回0,无法正确解析。

✅ 正确做法:先通过optString获取字符串,再手动转为对应数字类型,避免类型不匹配。

java 复制代码
// 错误示例
int age = json.optInt("age"); // 后端返回"18",返回0
// 正确示例
String ageStr = json.optString("age", "0");
int age = Integer.parseInt(ageStr);

3.2 布尔值解析坑

后端返回字符串"true"/"false"(如{"flag":"true"})时,optBoolean返回false,getBoolean抛异常。

✅ 正确做法:通过optString获取字符串,再与"true"比较判断。

java 复制代码
// 错误示例
boolean flag = json.optBoolean("flag"); // 返回false
// 正确示例
boolean flag = "true".equals(json.optString("flag", "false"));

3.3 精度丢失坑

金额、价格等字段,用getDouble/optDouble解析会导致精度丢失(如0.01变成0.0099999999)。

✅ 正确做法:用optString获取字符串,再转为BigDecimal类型。

java 复制代码
// 错误示例
double price = json.optDouble("price"); // 精度丢失
// 正确示例
String priceStr = json.optString("price", "0.00");
BigDecimal price = new BigDecimal(priceStr);

3.4 对象/数组判空坑

optJSONObject/optJSONArray返回null,而非空对象/空数组,直接调用方法(如length())会抛空指针。

✅ 正确做法:获取后先判空,再进行后续操作。

java 复制代码
// 正确示例(数组)
JSONArray list = json.optJSONArray("list");
if (list != null && list.length() > 0) {
    // 遍历数组
}

// 正确示例(对象)
JSONObject user = json.optJSONObject("user");
if (user != null && !user.isEmpty()) {
    // 获取对象中的字段
}

3.5 超大数字解析坑

雪花ID、订单号等超长数字(超过int范围),用getInt解析会抛异常,用optInt返回0。

✅ 正确做法:用optString获取,或用getLong/optLong解析(确保不超过long范围)。

4. 完整示例代码

以下示例涵盖日常解析常见场景,遵循上述规范,可直接参考使用:

java 复制代码
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.math.BigDecimal;

public class JsonParseDemo {
    public static void main(String[] args) {
        // 模拟后端返回的JSON字符串
        String jsonStr = "{" +
                "\"msgid\":\"123456\"," + // 必填字符串
                "\"name\":\"张三\"," + // 非必填字符串
                "\"age\":\"25\"," + // 非必填数字(字符串格式)
                "\"flag\":\"true\"," + // 布尔值(字符串格式)
                "\"price\":\"99.99\"," + // 金额
                "\"user\":{\"id\":1001,\"phone\":\"13800138000\"}," + // 子对象
                "\"list\":[{\"id\":1,\"title\":\"测试1\"},{\"id\":2,\"title\":\"测试2\"}]" + // 数组
                "}";

        try {
            JSONObject json = new JSONObject(jsonStr);

            // 1. 必填字段(getString)
            String msgid = json.getString("msgid");

            // 2. 非必填字符串(optString + 默认值)
            String name = json.optString("name", "未知用户");

            // 3. 非必填数字(先转字符串,再转int)
            String ageStr = json.optString("age", "0");
            int age = Integer.parseInt(ageStr);

            // 4. 布尔值(字符串判断)
            boolean flag = "true".equals(json.optString("flag", "false"));

            // 5. 金额(转BigDecimal)
            String priceStr = json.optString("price", "0.00");
            BigDecimal price = new BigDecimal(priceStr);

            // 6. 子对象(optJSONObject + 判空)
            JSONObject user = json.optJSONObject("user");
            String phone = "";
            if (user != null) {
                phone = user.optString("phone", "未知号码");
            }

            // 7. 数组(optJSONArray + 判空 + 遍历)
            JSONArray list = json.optJSONArray("list");
            if (list != null && list.length() > 0) {
                for (int i = 0; i < list.length(); i++) {
                    JSONObject item = list.getJSONObject(i);
                    int itemId = item.getInt("id");
                    String title = item.optString("title", "");
                    System.out.println("数组项:id=" + itemId + ", title=" + title);
                }
            }

            // 输出解析结果
            System.out.println("msgid:" + msgid);
            System.out.println("name:" + name);
            System.out.println("age:" + age);
            System.out.println("flag:" + flag);
            System.out.println("price:" + price);
            System.out.println("phone:" + phone);

        } catch (JSONException e) {
            // 捕获解析异常(如必填字段缺失、JSON格式错误)
            e.printStackTrace();
            System.out.println("JSON解析失败:" + e.getMessage());
        } catch (NumberFormatException e) {
            // 捕获数字转换异常
            e.printStackTrace();
            System.out.println("数字转换失败:" + e.getMessage());
        }
    }
}
相关推荐
NigulasiLiu1 小时前
CompletionService并发编排消费任务
java
Shadow(⊙o⊙)1 小时前
Linux进程地址空间——钻入Linux内核架构性剖析 硬核手搓!
java·linux·运维·服务器·开发语言·c++
Volunteer Technology1 小时前
Spring AI MCP案例
java·开发语言·数据库
紫琪软件工作室1 小时前
SpringBoot Java邮件发送工具类
java·spring boot·spring
郝学胜-神的一滴1 小时前
干货版《算法导论》04:渐近复杂度与序列接口实战
java·开发语言·数据结构·c++·python·算法
星栈1 小时前
投影挂了怎么办?我的 CQRS 三层容错方案
数据库·后端·开源
2301_811130541 小时前
【保姆级教程】Android Studio完整安装步骤(2026最新版,新手零踩坑)
android·java
杨运交1 小时前
[017][web模块]基于计数器的接口幂等性与访问限流设计实战
spring boot·后端
_Evan_Yao1 小时前
缓存与数据库的“双写悖论”:一致性的常见陷阱与破局之道
java·后端·缓存