41

I was implementing a Bitmap cache using a HashMap<Integer, Bitmap> and received the following warning in Eclipse:

Use new SparseArray(...) instead for better performance.

I've never heard of that class before, but inspecting it it doesn't seem to have a containsKey() method which I was calling on retrieval of a Bitmap from the cache to check if it exists in the cache, and if it doesn't, then add it.

Any ideas on the best way to check if the key already exists?

I guess I could change the code to use this overload and check for null?

Bitmap bitmap = cache.get(key, null); 
auselen
  • 25,874
  • 4
  • 67
  • 105
magritte
  • 6,801
  • 8
  • 52
  • 78

5 Answers5

48

You could use:

Bitmap bitmap = cache.get(key, null); 

But understand that this is the same as get(key):

Bitmap bitmap = cache.get(key); 

The best way to use get(key, default) is to provide a generic default case, something to is a valid substitute when the key is not found.

But there is no good reason not to use if(get(key) != null) as a quick replacement for contains().

Sam
  • 84,460
  • 18
  • 172
  • 171
  • Thanks Sam, good spot on the overload, I've gone with your suggestion of just replacing with if (get(key) != null). – magritte Sep 15 '12 at 22:53
32

Hence your value can be null in various situations, I'd suggest to useindexOfKey(int key) Here is the indexOfKey(int key) reference.

Then just simply check for negative return value

if(mySparseArray.indexOfKey(int) < 0) {
   //Item does not exist. Do something relevant 
}
Alex
  • 688
  • 6
  • 8
  • Is this better/worse than just using `.get`? – Smar Jan 17 '18 at 12:11
  • `.get(int)` is O(1) because it's checking the underlying array directly. `indexOf(int)` is O(log(n)) because it does a binary search to find the right index – mylovemhz Dec 14 '18 at 04:16
  • 1
    @mylovemhz Wrong! the `int` in `get(int)` is not an index, it's a key. Therefore, it's not O(1). Both `get(int)` and `indexOfKey(int)` have the same complexity O(log(n)), one returns the value in the position if found, null otherwise, the other only returns the index if found, a negative value otherwise. – Ace Feb 23 '19 at 08:22
  • 1
    True, both `get(int)` and `indexOfKey(int)` do binary search. My mistake. – mylovemhz Feb 24 '19 at 16:17
1

Quoting from documentation.

SparseArrays map integers to Objects. Unlike a normal array of Objects, there can be gaps in the indices. It is intended to be more efficient than using a HashMap to map Integers to Objects.

You can use get(int) which would also return null if key is not found. Like;

Bitmap bitmap = cache.get(key);

auselen
  • 25,874
  • 4
  • 67
  • 105
  • Key may have null value, in that case with your code you won't be able to determine whether key exists or not. i.e. if key is not exists it'll return null and if key has null value it'll return null too. indexOfKey should be user in this case (See Alex's answer) – user1991679 Sep 13 '15 at 11:45
  • @user1991679 quite old answer and what you suggest is I guess via newer apis. However answer to your comment is, int primitive can't be null. – auselen Sep 13 '15 at 12:28
  • I don't understand how the fact that primitive can't be null related to my comment. BTW, indexOfKey was introduced in API 1. – user1991679 Sep 13 '15 at 13:01
  • @uset1991679 ok I see what you mean now but I think question wasn't really about null values. Or that was my take. – auselen Sep 13 '15 at 13:47
  • @user1991679 thing is sparsearray isn't supposed to be a map. It is an array, very long one. Like normal array you should get an null value or reference back. If you need to check existance of keys then may be you need a map not an array. I think that's why Alex's answer is not relevant. – auselen Sep 13 '15 at 14:11
  • @user1991679 "key may have null value" -> "key may map to null value " I guess that's why I didn't get it first time. – auselen Sep 13 '15 at 14:14
1

Going by the implementation of SparseArray it seems counter-intuitive that it may have better performance (time-complexity) than HashMap (other than lower space-requirement which makes sense for a mobile environment) since the get() member of SparseArray uses binary-search (O(log N)) while for HashMap uses array-indexing(O(1)).

Providing the get() method implementation for both the classes (as-is):

public V get(Object key) { // for HashMap
    if (key == null)
        return getForNullKey();
    int hash = hash(key.hashCode());
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
            e != null;
            e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    return null;
}

public E get(int key, E valueIfKeyNotFound) {  //for SparseArray
    int i = binarySearch(mKeys, 0, mSize, key);

    if (i < 0 || mValues[i] == DELETED) {
        return valueIfKeyNotFound;
    } else {
        return (E) mValues[i];
    }
}

as to whether to use indexOfKey(key) < 0 or get(key) == null for checking existence of key in a SparseArray, anything is ok since both use binary-search underneath.

public int indexOfKey(int key) {  // for SparseArray
    if (mGarbage) {
        gc();
    }

    return binarySearch(mKeys, 0, mSize, key);
}
neel
  • 144
  • 4
0

Multiple ways:

  1. If you want to use the value that is associated to the key anyway, you can use get() :

    val sparseArray = SparseArray<String>()
    val someKey = 123
    val someValue: String? = sparseArray[someKey]
    if(someValue!=null){
        //do something
    }
    

Note that as opposed to what the IDE thinks, it can be null, which is why I added ? .

  1. if you just want to check if it exists, you can use indexOfKey(key) >= 0

  2. If you don't like the above, and want a more readable option, you can use containsKey of the ktx-collection dependency:

    implementation 'androidx.core:core-ktx:#'
    implementation 'androidx.collection:collection-ktx:#'
    

Usage:

    val sparseArray = SparseArray<String>()
    val someKey = 123
    if (sparseArray.containsKey(someKey)) {
        //do something
    }
android developer
  • 106,412
  • 122
  • 641
  • 1,128