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


422

Який кращий метод повернення нульових значень у JSON? Чи є інші переваги для примітивів?

Наприклад, якщо мій об’єкт на сервері має цілий номер, який називається "myCount" без значення, найбільш правильним JSON для цього значення буде:

{}

або

{
    "myCount": null
}

або

{
    "myCount": 0
}

Те саме питання для Strings - якщо у мене на сервері є нульова рядок "myString", це найкращий JSON:

{}

або

{
    "myString": null
}

або

{
    "myString": ""
}

або (лорд допоможи мені)

{
    "myString": "null"
}

Мені подобається умова про те, щоб колекції були представлені в JSON як порожня колекція http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html

Порожній масив буде представлений:

{
    "myArray": []
}

Підсумок EDIT

Аргумент "особистих уподобань" видається реалістичним, але короткозорий у тому, що ми, як громада, будемо споживати все більшу кількість різноманітних послуг / джерел. Конвенції про структуру 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()));
    }
}

Залежна залежність:

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

5
Не існує найкращого способу. Виберіть те, що найпростіше споживати клієнту у вашому конкретному випадку використання. В дусі повернення пустих колекцій замість того null, подумайте, чи краще ваш клієнт із порожньою рядком або null- рядок, що містить слово "null", не відрізняється від дійсного значення, не робіть цього.
Philipp Reichart

3
0 або порожній рядок цілком може мати інше значення від null, яке може мати інше значення від атрибута, який не існує. Якщо ви хочете представляти null, використовуйте null. Це найяскравіше.
Джон Шихан

У Objective-C є визначений NSNullклас, який має однотонний екземпляр. Посилання на цей екземпляр еквівалентна JSON null. Я б здогадався, що інша мова могла зробити те саме. Звичайно, потрібно було б перевірити клас отриманого об'єкта перед тим, як подавати його до передбачуваного класу, - як би це було "невідомо".
Гарячі лизання

2
Зауважте, що наявність "нульового" списку також не є найкращою практикою в Java: якщо очікується, що список буде порожнім, ініціалізуйте його у порожній список. Якщо потрібно , щоб залишатися порожнім (наприклад , тому що він буде замінений на оптовий новий список , а не змінений , щоб додати значення), відформатуйте її в в порожній список (тобто Collections.emptyList()). Це дозволяє уникнути нульових помилок, які в іншому випадку можуть заподіяти біль.
Periata Breatta

@HotLicks - це можливо лише тому, що Objective-C динамічно набирається. Наприклад, у Java у вас не міг бути (корисний) Nullклас, оскільки ви зможете призначити його значення лише об'єктам власного типу або типу Object.
Periata Breatta

Відповіді:


378

Давайте оцінимо аналіз кожного з них:

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

Це, ймовірно, призведе до неприємностей, тому що ви встановлюєте значення рядка нульовим; в цьому випадку, obj.myString == "null"однак, це не так == null .


JSON6 {"myArray": []}

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


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

207

nullне дорівнює нулю. Це не є цінністю, саме по собі : це значення поза області змінної , що вказує відсутніх або невідомих даних.

Є лише один спосіб представити nullв JSON. За специфікаціями ( RFC 4627 та json.org ):

2.1. Цінності

Значення JSON ОБОВ'ЯЗКОВО бути об'єктом, масивом, числом або рядком або одним із
наступні три буквальні назви:

  false null true

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


8
Це така ганьба, що нуль взагалі має бути присутнім. 4 символи ні за що. Було б добре просто виключити значення цілком. json = '{"myValue":}';
Річард А Квадлінг

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

13
@Dave May: "Значення JSON не є програмами" - Моя думка про однозначне означення сигналу про наміри. Так, це коштує додатково чотири символи, і для деяких додатків різниця може бути істотною. Однак у багатьох випадках переваги помилок виглядають неправильно, набагато переважують переваги незначних оптимізацій.
Скотт Сміт

11
@Dave Також, за інформацією json.org, JSON "людям легко читати і писати".
Sophivorus

14
Також зауважте, що якщо у вас проблеми з 4 символами ASCII, JSON не найкращий підхід, подивіться на Binary 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

Я б вибрав "за замовчуванням" для типу даних змінної ( nullдля рядків / об'єктів, 0для чисел), але дійсно перевірити, який код, який буде споживати об'єкт, очікує. Не забувайте, що іноді існує відмінність між null/ за замовчуванням та "немає".

Перевірте нульовий шаблон об'єкта - іноді краще передавати якийсь спеціальний об'єкт замість 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

Зауважте, що граматика форми McKeeman Form на правій бічній панелі пов'язаної сторінки специфікацій JSON підтверджує твердження, що голою nullє дійсним JSON. Текст основного тексту та ілюстрації там неоднозначні, і якщо щось здається, що вони підказують, то в корені дійсні лише об'єкти та масиви.
yoyoyoyosef
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.