Search code examples
javahashmutable

How to detect if a list is changed?


I have a List field in a class managed by a little-known proprietary framework.

The annotation @BindMagic is managed by the framework, so the underlying list mutates sometimes: it could be recreated or its elements could change.

class SharedEntity{

  @BindMagic // this annotation does a magic that we cannot control
  private List<Map<String,Object>> values;

  public boolean isChangedSincePreviousCall(){
    // check if "values" have changed since the previous call of this method          
  }
}

I'm agree that it is a poor design, but let's suppose there's no possibility to affect it.

Time to time (not on every mutation) it's needed to check if the list is changed. For instance, I want do it with the method isChangedSincePreviousCall. Probably, something like a hash sum would be good. But I'm curious are there better ways.

What is the best practice to detect if the list is changed?


Solution

  • Using a hash is not definitive, because the same hash can be produced from different inputs, albeit with a very small chance.

    "Being changed" and "being different" mean different things. Consider an entry in one of the maps that is changed from "A" -> 1 to "A" -> 2 then back to "A" -> 1 again between calls to your method - it was changed but isn't different. I'll assume you mean "different".

    Make a copy when checking and compare that with the current state. Assuming that the map values are immutable:

    class SharedEntity {
    
        @BindMagic
        private List<Map<String, Object>> values;
        private List<Map<String, Object>> valuesCopy;
    
        public boolean isChangedSincePreviousCall() {
            newCopy = new ArrayList<>(values);
            boolean result = !Objects.equals(valuesCopy, newCopy);
            valuesCopy = newCopy;
            return result;
        }
    }
    

    If the Map values are (or contain) mutable objects, you'll have to make a deep copy of them when creating the copy.

    FYI Objects#equals() returns true if both parameters are null.