Представляя нуль в JSON


424

Каков предпочтительный метод для возврата нулевых значений в JSON? Есть ли другое предпочтение примитивам?

Например, если мой объект на сервере имеет Integer с именем «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 помогут нормализовать потребление и повторное использование указанных услуг. Что касается установления стандарта, я бы предложил принять большинство соглашений Джексона с несколькими исключениями:

  • Объекты предпочтительнее примитивов.
  • Пустые коллекции предпочтительнее нуля.
  • Объекты без значения представлены как ноль.
  • Примитивы возвращают свою ценность.

Если вы возвращаете объект JSON с большей частью нулевыми значениями, у вас может быть кандидат на рефакторинг в несколько сервисов.

{

    "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>

5
Там нет лучшего способа. Выберите, что проще всего потреблять для клиента в вашем конкретном случае использования. В духе возврата пустых коллекций вместо того null, подумайте, лучше ли ваш клиент с пустой строкой или null- строка, содержащая слово «ноль», неотличима от допустимого значения, не делайте этого.
— Филипп Рейхарт

3
0 или пустая строка вполне может иметь значение, отличное от нуля, которое может иметь значение, отличное от атрибута, который не существует. Если вы хотите представить null, используйте null. Это самое явное.
— Джон Шиэн

В Objective-C есть определенный NSNullкласс, который имеет единственный экземпляр. Ссылка на этот экземпляр эквивалентна JSON null. Я предполагаю, что другой язык может сделать то же самое. Конечно, нужно было бы проверить класс полученного объекта перед приведением к предполагаемому классу - быть как бы «осведомленным о нуле».
— Hot Licks

2
Обратите внимание, что наличие «нулевого» списка также не рекомендуется в Java: если ожидается, что список будет пустым, инициализируйте его как пустой список. Если требуется оставить пустым (например, потому что он будет заменен оптом новым списком, а не изменен для добавления значений), инициализируйте его в пустом списке (то есть Collections.emptyList()). Это позволяет избежать ошибок с нулевыми ссылками, которые в противном случае могут причинить боль.
— Периата Breatta

@HotLicks - это возможно только потому, что Objective-C динамически типизирован. В Java, например, у вас не может быть (полезного) Nullкласса, потому что вы сможете назначать его значения только объектам его собственного типа или типа Object.
— Периата Breatta

Ответы:


380

Давайте оценим разбор каждого:

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 переменной является способом JSON спецификации указывает , nullдолжны быть представлены. Но, как всегда, это зависит от того, что вы делаете - иногда «правильный» способ сделать это не всегда работает в вашей ситуации. Используйте свое суждение и примите обоснованное решение.


JSON1 {}

Это возвращает пустой объект. Там нет никаких данных, и он только скажет вам, что любой ключ, который вы ищете (будь то myCountили что-то еще), имеет тип undefined.


JSON2 {"myCount": null}

В этом случае myCountфактически определяется, хотя его значение null. Это не то же самое, что и «нет, undefinedи нет null», и если вы тестировали одно или другое условие, это могло бы быть успешным, в то время как JSON1 не выполнялся.

Это точный способ представления в nullсоответствии со спецификацией JSON .


JSON3 {"myCount": 0}

В этом случае myCount равен 0. Это не то же самое null, и это не то же самое, что false. Если ваше условное утверждение оценивает myCount > 0, то это может быть полезно. Более того, если вы выполняете расчеты на основе значения здесь, 0 может быть полезным. Если вы пытаетесь проверить, nullоднако, это на самом деле не будет работать вообще.


JSON4 {"myString": ""}

В этом случае вы получаете пустую строку. Опять же, как и в JSON2, он определен, но он пуст. Вы можете проверить, if (obj.myString == "")но вы не можете проверить nullили undefined.


JSON5 {"myString": "null"}

Это, вероятно, доставит вам неприятности, потому что вы устанавливаете строковое значение в null; в этом случае, obj.myString == "null"однако это не так == null .


JSON6 {"myArray": []}

Это скажет вам, что ваш массив myArrayсуществует, но он пуст. Это полезно, если вы пытаетесь выполнить подсчет или оценку myArray. Например, предположим, что вы хотите оценить количество фотографий, опубликованных пользователем, - вы можете сделать это, myArray.lengthи он вернется 0: определено, но фотографий не опубликовано.


1
Большое спасибо, очень полезно. Просто маленький боковой узел; когда Play Json (scala) сериализует Option [String] = Нет результата, JSON1т. е.{}
— Нейл

207

nullне ноль. По сути, это не значение : это значение вне области переменной, указывающее на отсутствующие или неизвестные данные.

Существует только один способ представления nullв JSON. Согласно спецификации ( RFC 4627 и json.org ):

2.1. Ценности

Значение JSON ДОЛЖНО быть объектом, массивом, числом или строкой или одним из
следующие три буквальных имени:

  ложь ноль истина

введите описание изображения здесь


8
Это такой позор, что ноль должен присутствовать вообще. 4 символа ни за что. Было бы неплохо просто полностью исключить значение. json = '{"myValue":}';
— Ричард A Quadling

119
@Richard A Quadling - я последователь Хэла Абельсона "Программы должны быть написаны для того, чтобы люди могли их читать, и только для машин - для запуска". Я бы предпочел слово «ноль», подтверждающее намерение программиста, а не просто вопрос случайного упущения.
— Скотт Смит

13
@ Дэйв Мэй: «Значения JSON не являются программами» - моя точка зрения о недвусмысленном сигнале о намерении. Да, это стоит дополнительных четырех символов, и для некоторых приложений разница может быть значительной. Тем не менее, во многих случаях выгоды от ошибок выглядят неправильно, значительно перевешивая преимущества незначительных оптимизаций.
— Скотт Смит

11
@Dave Кроме того, согласно json.org, JSON «людям легко читать и писать».
— Софивор

14
Также обратите внимание, что если у вас есть проблемы с 4 символами ASCII, JSON - не лучший подход, посмотрите на двоичный JSON или лучше на чистый двоичный формат.
— PhoneixS

26

Есть только один способ представлять 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 не должно совпадать с json (хотя это так).
— Младен Б.

15

Я хотел бы использовать, nullчтобы показать, что нет никакого значения для этого конкретного ключа. Например, используйте nullдля представления того, что «количество устройств в вашей семье, подключенных к Интернету» неизвестно.

С другой стороны, используйте, {}если этот конкретный ключ не применим. Например, вы не должны показывать счет, даже если nullна вопрос «количество автомобилей с активным интернет-соединением» задается тот, у кого нет автомобилей.

Я бы не стал использовать любое значение по умолчанию, если это значение не имеет смысла. Хотя вы можете решить использовать nullдля представления никакой ценности, конечно, никогда не используйте "null"для этого.


7

Я бы выбрал «default» для типа данных переменной ( nullдля строк / объектов, 0для чисел), но на самом деле проверил, какой код ожидает этот объект. Не забывайте, что иногда есть различие между null/ default и «не присутствует».

Проверьте шаблон нулевого объекта - иногда лучше передать какой-то специальный объект вместо null(то есть []массив вместо nullмассивов или ""для строк).


2

Это личный и ситуативный выбор. Важно помнить, что пустая строка и число ноль концептуально отличаются от null.

В случае a countвы, вероятно, всегда хотите какое-то действительное число (если countоно неизвестно или не определено), но в случае строк, кто знает? Пустая строка может что- то значить в вашем приложении. Или, может быть, это не так. Это решать вам.


1

Согласно спецификации JSON , внешний контейнер не обязательно должен быть словарем (или «объектом»), как подразумевается в большинстве комментариев выше. Это также может быть список или пустое значение (т. Е. Строка, число, логическое значение или ноль). Если вы хотите представить нулевое значение в 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, которая подтверждает утверждение, что голые nullобразуют действительный JSON. Основной основной текст и иллюстрации там неоднозначны, и, если что-то и предполагает, что в корне допустимы только объекты и массивы.
— yoyoyoyosef
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.