使用double作为比较违反合同对JSONArray进行排序?

时间:2017-11-27 12:15:50

标签: java android sorting comparison

我正在尝试对JSONArray进行排序,但是我收到以下错误:

 Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
     at java.util.TimSort.mergeHi(TimSort.java:895)
     at java.util.TimSort.mergeAt(TimSort.java:512)
     at java.util.TimSort.mergeForceCollapse(TimSort.java:453)
     at java.util.TimSort.sort(TimSort.java:250)
     at java.util.Arrays.sort(Arrays.java:1523)
     at java.util.Collections.sort(Collections.java:238)

这是我的代码:

private JSONArray SortJSONArray(String json) {
        JSONArray sortedJsonArray = new JSONArray();

        try {
            JSONArray jsonArr = new JSONArray(json);

            List<JSONObject> jsonValues = new ArrayList<JSONObject>();
            for (int i = 0; i < jsonArr.length(); i++) {
                jsonValues.add(jsonArr.getJSONObject(i));
            }
            Collections.sort(jsonValues, new Comparator<JSONObject>() {
                private static final String KEY_NAME = "EUR";

                @Override
                public int compare(JSONObject a, JSONObject b) {
                    Double valA = 0.0;
                    Double valB = 0.0;

                    try {
                        valA = a.getDouble(KEY_NAME);
                        valB = b.getDouble(KEY_NAME);
                    } catch (JSONException e) {
                        Log.e("MainActivity", e.getMessage());
                    }

                    if(valA < valB) {
                        return -1;
                    } else if( valB < valA) {
                        return 1;
                    } else {
                        return 0;
                    }
                }
            });

            for (int i = 0; i < jsonArr.length(); i++) {
                sortedJsonArray.put(jsonValues.get(i));
            }
        } catch (JSONException e) {
            Log.e("MainActivity", e.getMessage());
        }
        return sortedJsonArray;
    }

2 个答案:

答案 0 :(得分:3)

问题是a.getDouble(KEY_NAME)b.getDouble(KEY_NAME)可能会引发异常。

如果a.getDouble(KEY_NAME)引发异常且b.getDouble(KEY_NAME)没有,b.getDouble(KEY_NAME)永远不会被评估,valAvalB仍然是0.0

另一方面,如果您将ab进行比较(即调用compare(b,a)而不是compare(a,b),则会先评估b.getDouble(KEY_NAME) a.getDouble(KEY_NAME)会引发异常,因此valA0.0valB会有其他值。

在这种情况下,compare(a,b)将返回0compare(b,a)将返回非零值(假设b.getDouble(KEY_NAME)不返回0.0),违反了Comparator的合同。

在单独的try块中评估a.getDouble(KEY_NAME)b.getDouble(KEY_NAME)将解决此问题。

                try {
                    valA = a.getDouble(KEY_NAME);
                } catch (JSONException e) {
                    Log.e("MainActivity", e.getMessage());
                }
                try {
                    valB = b.getDouble(KEY_NAME);
                } catch (JSONException e) {
                    Log.e("MainActivity", e.getMessage());
                }

                return Double.compare(valA,valB);

答案 1 :(得分:0)

解决方法是在catch语句中返回一个值:

try {
    valA = a.getDouble(KEY_NAME);
        valB = b.getDouble(KEY_NAME);
    } catch (JSONException e) {
        Log.e("MainActivity", e.getMessage());
        return -10;
    }

    if(valA < valB) {
        return -1;
    } else if( valB < valA) {
        return 1;
    } else {
        return 0;
    }