Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: compare HashMap<String, Object> if value might be an Object[]

I have the following HashMap with properties keys and values:

private HashMap<String, Object> prop_values;

I need to check if one instance of it is equal to another one. In the past, i just did this:

if (prop_values_1.equals(prop_values_2)){
   //  do something
}

And this worked until i got Object[] as a value. So, my previous expression always returned false on such HashMap with any Object[] value.

So, i have to implement this method:

private boolean isPropValuesEquals(HashMap<String, Object> pv1, HashMap<String, Object> pv2){
   boolean isEquals = true;

   if (pv1 == null || pv2 == null){
      return false;
   }

   if (!pv1.keySet().equals(pv2.keySet())){
      return false;
   }

   for (String key : pv1.keySet()){

      Object cur_pv1 = pv1.get(key);
      Object cur_pv2 = pv2.get(key);

      if (cur_pv1 instanceof Object[]){
         if (cur_pv2 instanceof Object[]){
            isEquals = Arrays.equals((Object[])cur_pv1, (Object[])cur_pv2);
         } else {
            return false;
         }
      } else {
         isEquals = isEquals && cur_pv1.equals(cur_pv2);
      }

      if (!isEquals){
         return false;
      }
   }

   return isEquals;

}

It works, but it seems to be some kind of hack, and i'm not sure this is the best way to achieve what I need.

So, here's two questions:

  • why Object[].equals() is not the same as Arrays.equals()? It seems to be painful.

  • is there some better way to compare HashMap<String, Object>, if values can be an Object[] ?

like image 433
Dmitry Frank Avatar asked Apr 19 '12 07:04

Dmitry Frank


1 Answers

The deep problem is that an there's no way to override the equals() of an array. Why it's not written as "equal elements in the same order" in the first place, I have no idea. It definitely could have been (unless there's some obscure rationale for not doing it; I can't think of any; if you wanted to check for reference equality, you use ==, so what would a working equals() harm?).

Your solution is the way to go. Just a couple of details to consider:

  • Instead of x instanceof Object[], you could use x.getClass().isArray(), so it would work for other arrays as well, such as int[] (which is not a subclass of Object[]). Downside: you may have to separately check if x is null.

  • If the arrays may contain nested arrays, consider using Arrays.deepEquals().

A demonstration that primitive arrays are not Object[]s:

    Object a = new int[1];
    System.out.println("" + (a instanceof Object[])); // false
    System.out.println("" + a.getClass().isArray()); // true

Yet another pain in the arse is that even if you find that x is an array, you still have to handle separately cases for all the different primitive element types. There's no way to handle them in a generic way in Java's type system. Of course, if you don't have primitive arrays in our map, then you don't need to handle this case.

like image 179
Joonas Pulakka Avatar answered Nov 11 '22 04:11

Joonas Pulakka