在 JSON 中表示 null 的方法

630

在 JSON 中,返回空值的首选方法是什么?原始数据类型是否有不同偏好?

例如,如果我的服务器对象中有一个名为“myCount”的整数,但没有值,则该值的最正确 JSON 是:

{}
或者
{
    "myCount": null
}
{
    "myCount": 0
}

如果在服务器上我有一个空字符串"myString",那么最好的JSON是什么?

{}
或者
{
    "myString": null
}
或者
{
    "myString": ""
}

或者(上帝保佑我)

{
    "myString": "null"
}

我喜欢将集合表示为JSON中的空集合的惯例。http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html

一个空数组将被表示为:

{
    "myArray": []
}

编辑摘要

"个人偏好"的论点似乎是现实的,但是这种看法是短视的,因为作为一个社区,我们将消耗越来越多不同的服务/来源。制定JSON结构的约定将有助于规范所述服务的使用和重复利用。至于建立标准,我建议采用大部分Jackson约定,但有一些例外:

  • 对象优先于基元。
  • 空集合优先于null。
  • 没有值的对象表示为null。
  • 基元返回其值。

如果您返回的JSON对象大多数都是null值,则可能需要将其重构为多个服务。

{
    "value1": null,
    "value2": null,
    "text1": null,
    "text2": "hello",
    "intValue": 0, //use primitive only if you are absolutely sure the answer is 0
    "myList": [],
    "myEmptyList": null, //NOT BEST PRACTICE - return [] instead
    "boolean1": null, //use primitive only if you are absolutely sure the answer is true/false
    "littleboolean": false
}

以上 JSON 是从以下 Java 类生成的。

package jackson;    
import java.util.ArrayList;
import java.util.List;    
import com.fasterxml.jackson.databind.ObjectMapper;
    
public class JacksonApp {    
    public static class Data {    
        public Integer value1;    
        public Integer value2;
        public String text1;
        public String text2 = "hello";
        public int intValue;
        public List<Object> myList = new ArrayList<Object>();
        public List<Object> myEmptyList;
        public Boolean boolean1;
        public boolean littleboolean;   
   }
    
   public static void main(String[] args) throws Exception {
       ObjectMapper mapper = new ObjectMapper();
       System.out.println(mapper.writeValueAsString(new Data()));
   }
}

Maven 依赖:

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

7
没有最好的方法。在具体的使用情况下,选择对客户最易于消化的方式。类似于返回空集合而非null,请考虑您的客户端是否更适合使用空字符串或null——包含单词"null"的字符串与有效值无法区分,不要这样做。 - Philipp Reichart
6
空值或空字符串与null有不同的含义,而属性不存在也与之不同。如果想要表示null,请使用null。这是最明确的方式。 - John Sheehan
1
在 Objective-C 中,有一个定义好的 NSNull 类,它拥有一个单例实例。对该实例的引用相当于 JSON 的 null。我想其他语言也可以做到这一点。当然,在强制转换为预定类之前,必须检查接收到对象的类别——要有“空值意识”。 - Hot Licks
2
请注意,在Java中,拥有一个“null”列表也不是最佳实践:如果预期列表为空,请将其初始化为空列表。如果需要保持为空(例如,因为它将被整个替换为新列表而不是修改以添加值),请将其初始化为空列表(即Collections.emptyList())。这样做可以避免空引用错误,否则可能会很麻烦。 - Periata Breatta
@HotLicks - 这只有在Objective-C动态类型的情况下才可能实现。例如,在Java中,你无法拥有一个(有用的)Null类,因为你只能将其值分配给其自身类型或Object类型的对象。 - Periata Breatta
@PeriataBreatta 你把“空指针”和“空值”混淆了。前者是不好的,后者却没问题。 - Henry Henrinson
8个回答

549

让我们评估每个的解析:

http://jsfiddle.net/brandonscript/Y2dGv/

var json1 = '{}';
var json2 = '{"myCount": null}';
var json3 = '{"myCount": 0}';
var json4 = '{"myString": ""}';
var json5 = '{"myString": "null"}';
var json6 = '{"myArray": []}';

console.log(JSON.parse(json1)); // {}
console.log(JSON.parse(json2)); // {myCount: null}
console.log(JSON.parse(json3)); // {myCount: 0}
console.log(JSON.parse(json4)); // {myString: ""}
console.log(JSON.parse(json5)); // {myString: "null"}
console.log(JSON.parse(json6)); // {myArray: []}

简而言之:

json2变量中的片段是表示null应该如何表示的JSON规范。但一如既往,它取决于你在做什么 - 有时候,“正确”的方法并不总是适合你的情况。请自行判断并做出明智的决定。


JSON1 {}

返回一个空对象。这里没有数据,只会告诉你你正在查找的任何键(无论是myCount还是其他)的类型为undefined


JSON2 {"myCount": null}

在这种情况下,myCount实际上已定义,尽管其值为null。这与“既不是undefined也不是null”不同,如果你测试其中一种条件,可能会成功,而JSON1将失败。

这是根据JSON规范表示null的最终方式。


JSON3 {"myCount": 0}

在这种情况下,myCount为0。这与null不同,也与false不同。如果你的条件语句评估myCount > 0,那么这可能是有价值的。此外,如果你基于这里的值运行计算,0可能很有用。但是,如果你试图测试null,那么这实际上根本不会起作用。


JSON4 {"myString": ""}

在这种情况下,你得到一个空字符串。与JSON2一样,它是定义过的,但是它是空的。你可以测试if (obj.myString == ""),但你不能测试nullundefined


JSON5 {"myString": "null"}

这可能会让你陷入麻烦,因为你将string值设置为null;在这种情况下,obj.myString == "null",但它不等于== null


JSON6 {"myArray": []}

这将告诉你你的数组myArray存在,但是它是空的。如果你试图对myArray执行计数或评估操作,这很有用。例如,假设你想要评估用户发布的照片数量 - 你可以做myArray.length,它将返回0:已定义,但没有发布的照片。


1
非常感谢,非常有帮助。只是一个小的侧面节点; 当Play Json(scala)序列化Option [String] = None结果为JSON1,即{} - Neil
2
有没有{"myObject": {}}的选项?可以将值设置为空对象吗? - jaquinocode
1
当然可以。它意味着与null不同的东西。 - brandonscript

266

null 不是零。它本身不是一个值:它是指示缺失或未知数据的变量域之外的值。

在 JSON 中,只有一种方式来表示 null。根据规范(RFC 4627json.org):

2.1. 值
JSON 值必须是对象、数组、数字或字符串,或以下三个字面名称之一:
false null true

输入图像说明


11
null 的存在实在太遗憾了,多了四个字符却没有任何意义。更好的方式是完全排除这个值。json = '{"myValue":}'; - Richard A Quadling
176
我是Hal Abelson“程序必须为人而写,机器只是执行的工具”的追随者。我更喜欢使用“null”这个词来确认程序员的意图,而不仅仅是意外遗漏的问题。 - Scott Smith
20
@Dave May: "JSON的值不是程序" - 我的观点是要以明确的方式传达意图。 是的,这会多花四个字符,对于某些应用程序来说,这种差异可能很重要。 然而,在许多情况下,使错误“看起来不对”所带来的好处远远超过小优化所带来的好处。 - Scott Smith
13
根据json.org,JSON“易于人类阅读和编写”。 - Sophivorus
21
请注意,如果您在处理4个ASCII字符时遇到问题,JSON可能不是最佳选择,请考虑使用二进制JSON或更好的纯二进制格式。 - PhoneixS
显示剩余3条评论

47

表示 null 的唯一方式是使用 null

console.log(null === null);   // true
console.log(null === true);   // false
console.log(null === false);  // false
console.log(null === 'null'); // false
console.log(null === "null"); // false
console.log(null === "");     // false
console.log(null === []);     // false
console.log(null === 0);      // false

也就是说,如果使用===操作符的任何消费您的JSON表示形式的客户端可能会遇到问题。

无值

如果您想表达一个对象具有属性myCount但其没有值:

{ "myCount": null }

没有属性/缺失属性

如果您想传达一个没有属性的对象:

{}

客户端代码将尝试访问myCount并得到undefined,因为它不存在。

空集合

如果您要表达一个带有属性myCount的对象,该属性是一个空列表:

{ "myCount": [] }

1
有一个很好的例子进行比较,但区分JavaScript和JSON会更有帮助,意思是,在JavaScript中表示null并不一定要匹配JSON的表示方式(尽管它们是相同的)。 - Mladen B.

17

我将使用 null 来表示该特定键没有值。例如,使用 null 表示“您家中连接到互联网的设备数量”未知。

另一方面,如果该特定键不适用,则使用 {}。例如,在询问没有任何汽车的人“具有活动互联网连接的汽车数量”时,不应显示计数,即使是null

除非默认值有意义,否则我会避免将任何值设为默认值。尽管你可以决定使用null来表示没有值,但绝对不要使用"null"这个字符串来做到这一点。


9
我会选择变量的数据类型为“默认”(对于字符串/对象为null,对于数字为0),但确保检查将使用该对象的代码需要什么类型。不要忘记有时候null/默认值和“不存在”的区别。
请查看null object pattern - 有时候最好传递一些特殊的对象而不是null(例如,使用[]数组代替null或使用""代替字符串)。

4
根据JSON规范,最外层的容器不一定是一个字典(或“对象”),这与上面大多数评论所暗示的不同。它也可以是一个列表或一个裸值(即字符串、数字、布尔或null)。如果你想在JSON中表示一个空值,整个JSON字符串(不包括包含JSON字符串的引号)就是null。没有大括号,没有方括号,没有引号。你可以指定一个包含空值键的字典({"key1":null}),或者一个包含空值的列表([null]),但它们本身并不是空值 - 它们是合适的字典和列表。同样,一个空字典({})或一个空列表([])也是完全可以的,但它们也不是空值。

在Python中:

>>> print json.loads('{"key1":null}')
{u'key1': None}
>>> print json.loads('[null]')
[None]
>>> print json.loads('[]')
[]
>>> print json.loads('{}')
{}
>>> print json.loads('null')
None

请注意,链接的JSON规范页面右侧边栏中的McKeeman Form语法验证了裸null构成有效的JSON的断言。主体文本和插图含糊不清,如果有什么建议,似乎只有对象和数组在根处是有效的。 - yoyoyoyosef

2

这是一个个人和情境选择。重要的是要记住,空字符串和数字零在概念上与null不同。

count的情况下,您可能总是希望有一些有效的数字(除非count未知或未定义),但在字符串的情况下,谁知道呢?在您的应用程序中,空字符串可能意味着某些东西。或者也许不意味着任何东西。这取决于您自己的决定。


1

'null'在实际使用中更佳

顺便提一下,以PHP为例,PHP将空集解释为由PHP创建的条目...

// This loop will iterate one item with the value 'the car'
$empty_json = '["the car"]';
$some_json_array = json_decode($empty_json);

foreach ($some_json_array as $i) {
  echo "PHP sees one item";
}

输出: PHP看到了汽车

// This loop will iterate one item, but with no values
$empty_json = '[""]';
$some_json_array = json_decode($empty_json);

foreach ($some_json_array as $i) {
  echo "PHP sees: $i";
}

输出:PHP看到

// This loop will iterate nothing because PHP's `json_decode()` function knew it was `null`
$empty_json = 'null';
$some_json_array = json_decode($empty_json);

foreach ($some_json_array as $i) {
  echo "PHP sees one item";
}

输出:(没有东西,foreach 不会循环)


这个问题不仅限于JavaPython,虽然问题中有一个Java示例,另一个答案中有一个Python示例。这个答案展示了一些PHP的内容,以补充答案所涵盖的领域。 - Jesse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接