Представляя нуль в 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>
pherris
источник
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: определено, но фотографий не опубликовано.

brandonscript
источник
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": [] }
dnozay
источник
+1 хороший пример со сравнениями, но было бы полезно различать javascript и json, что означает, что представление нуля в javascript не должно совпадать с json (хотя это так).
Младен Б.
15

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

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

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

marcoseu
источник
7

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

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

Алексей Левенков
источник
2

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

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

Wayne
источник
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
iggie
источник
Обратите внимание, что это грамматика формы МакКимана на правой боковой панели связанной страницы спецификаций JSON, которая подтверждает утверждение, что голые nullобразуют действительный JSON. Основной основной текст и иллюстрации там неоднозначны, и, если что-то и предполагает, что в корне допустимы только объекты и массивы.
yoyoyoyosef