3

我在JSONObject.toString(int)文档中注意到了这一点

抛出: JSONException - 如果对象包含无效数字。

如果事先完成了 NaN/Infinity 检查(在解析和类似的语句中),对象怎么可能包含无效数字.put("blah", Double.NAN)?哪些语句会抛出该异常?

我还在文档中读到没有 args 的.toString()不会抛出任何东西,所以我认为异常可能与作为参数传递的整数有关;但即使为零、负数或 Integer.MAX/MIN_VALUE 它仍然有效。

那么,当人们期望 .toString(int) 抛出异常时,应该如何处理呢?

4

3 回答 3

2

toString()方法不抛出异常,因为它必须覆盖public void toString()方法的签名java.lang.Object。在org.json.JSONObject泛型toString()方法中实际上会默默地失败,因为源代码是:

/**
 * Make a JSON text of this JSONObject. For compactness, no whitespace is
 * added. If this would not result in a syntactically correct JSON text,
 * then null will be returned instead.
 * <p>
 * Warning: This method assumes that the data structure is acyclical.
 *
 * @return a printable, displayable, portable, transmittable representation
 *         of the object, beginning with <code>{</code>&nbsp;<small>(left
 *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
 *         brace)</small>.
 */
public String toString() {
    try {
        return this.toString(0);
    } catch (Exception e) {
        return null;
    }
}

该方法依赖于toString(int)方法,如果它抛出异常,它会捕获它并返回null。

根据描述,当其中一个元素中包含无效数字toString(int)时,将引发异常;org.json.JSONObject但是查看代码可能是由于其他原因引发了此异常。

当您使用toString(int)堆栈跟踪 finally 调用write() 方法来解析对象本身时,从 json 对象到字符串的某些转换可能会引发异常:

static final Writer writeValue(Writer writer, Object value,
            int indentFactor, int indent) throws JSONException, IOException {
        if (value == null || value.equals(null)) {
            writer.write("null");
        } else if (value instanceof JSONObject) {
            ((JSONObject) value).write(writer, indentFactor, indent);
        } else if (value instanceof JSONArray) {
            ((JSONArray) value).write(writer, indentFactor, indent);
        } else if (value instanceof Map) {
            new JSONObject((Map<String, Object>) value).write(writer, indentFactor, indent);
        } else if (value instanceof Collection) {
            new JSONArray((Collection<Object>) value).write(writer, indentFactor,
                    indent);
        } else if (value.getClass().isArray()) {
            new JSONArray(value).write(writer, indentFactor, indent);
        } else if (value instanceof Number) {
            writer.write(numberToString((Number) value));
        } else if (value instanceof Boolean) {
            writer.write(value.toString());
        } else if (value instanceof JSONString) {
            Object o;
            try {
                o = ((JSONString) value).toJSONString();
            } catch (Exception e) {
                throw new JSONException(e);
            }
            writer.write(o != null ? o.toString() : quote(value.toString()));
        } else {
            quote(value.toString(), writer);
        }
        return writer;
    }

但是,如果正如您在问题中所说(以及@Carlos Rodriguez 评论),所有检查都是在创建对象时执行的,那么toString(int)方法可能永远不会引发异常。

希望能帮助到你,

于 2015-08-18T13:29:46.043 回答
1

它有助于查看JSONObject.toString(int)and的实现JSONObject.toString()

public String toString(int indentFactor) throws JSONException {
    StringWriter w = new StringWriter();
    synchronized (w.getBuffer()) {
        return this.write(w, indentFactor, 0).toString();
    }
} 

write方法写入 aWriter并将任何 IOException 重新抛出为 JSONException。如果你的分析是正确的,那么这样的 IOException 就永远不会发生,因为 StringWriters 也不会抛出 IOExceptions。因此,让这个方法抛出 JSONException 似乎只是一个实现决定,并且文档具有误导性。

public String toString() {
    try {
        return this.toString(0);
    } catch (Exception e) {
        return null;
    }
} 

实现证实了这一分析:在这里,API 设计人员决定捕获任何异常,这只有在从未抛出toString()异常时才有意义。

将这两个方法从其签名中的 throw 子句中释放出来try-catch可能会更好。toString(int)

于 2015-08-18T13:30:07.263 回答
0

我刚刚遇到这个问题。

这是一个示例,它将导致该JSONObject.toString(int)方法抛出一个JSONException

public static void main(String[] args) {
    Map<String, Double> map = new HashMap<>();
    map.put("num", Double.NaN);
    JSONObject obj = new JSONObject();
    obj.put("map", map);
    obj.toString(0);
}

在我看来,该方法应该抛出异常JSONObject.put(),但显然这里没有进行检查......

于 2017-10-20T09:16:53.013 回答