代码之家  ›  专栏  ›  技术社区  ›  TomSelleck

使用double作为比较来排序JSONArray违反了契约?

  •  2
  • TomSelleck  · 技术社区  · 8 年前

    我试图对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 回复  |  直到 8 年前
        1
  •  3
  •   Eran    8 年前

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

    如果 a、 getDouble(键名称) 引发异常并 b、 getDouble(键名称) 没有, b、 getDouble(键名称) valA valB 保持 0.0

    另一方面,如果你比较 a b 顺序相反(即调用 compare(b,a) 而不是 compare(a,b) , b、 getDouble(键名称) 将在之前进行评估 a、 getDouble(键名称) 引发异常,因此 瓦拉 0 valB公司

    那样的话 比较(a,b) 将返回 0 比较(b,a) 将返回非零值(假设 b、 getDouble(键名称) 不返回 0 ),违反了 Comparator .

    评价 a、 getDouble(键名称) b、 getDouble(键名称) 在单独的try块中可以解决该问题。

                    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);
    
        2
  •  0
  •   TomSelleck    8 年前

    解决方法是在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;
        }