5

So I was writing some very simple code and found a very unexpected behavior. All List and Map implementations use the equals method of a node to compare them. So if you would've a list of strings, and you would try to acquire the index of a string in the list, you don't need to use the same object. Example:

List<String> list = new ArrayList<>();
list.add("test");
int index = list.indexOf("test");
System.out.println(index);//returns 0

I've noticed that all the SparseArray classes of Android use == instead of equals to compare nodes. Example method (LongSparseArray.java):

public int indexOfValue(E value) {
    if (mGarbage) {
    gc();
    }

for (int i = 0; i < mSize; i++) {
    if (mValues[i] == value) {
        return i;
        }
    }
        return -1;
}

So if you have simple code like this:

LongSparseArray<String> localContacts = new LongSparseArray<>();
localContacts.put(2, "test");
int index = localContacts.indexOfValue("test");
System.out.println(index);

The index here would return -1 (which is pretty unexpected if you don't how the value is compared).

So I was wondering... why does Android not use equals? This is way more handy and preferred (from a Java point of view). Now I have to loop through all the values of a SparseArray and compare them my self, which results in more (unneeded) code (or use a Map which causes less performance in Android).

Displee
  • 670
  • 8
  • 20
  • Looks as though you can use `indexOfValueByValue` to use an equals comparison (Edit: Never mind, I see that that's hidden for some reason) – PPartisan Oct 09 '19 at 08:51

1 Answers1

2

Looking at the source code for LongSparseArray, it appears this method does exist - but that it's hidden (for some reason):

/**
* Returns an index for which {@link #valueAt} would return the
* specified key, or a negative number if no keys map to the
* specified value.
* <p>Beware that this is a linear search, unlike lookups by key,
* and that multiple keys can map to the same value and this will
* find only one of them.
* <p>Note also that this method uses {@code equals} unlike {@code indexOfValue}.
* @hide
*/
public int indexOfValueByValue(E value) {
    if (mGarbage) {
        gc();
    }

    for (int i = 0; i < mSize; i++) {
        if (value == null) {
            if (mValues[i] == null) {
                return i;
            }
        } else {
            if (value.equals(mValues[i])) {
                return i;
            }
        }
    }
    return -1;
}

You can see that all this code is really doing is what you said in your question - looping through all values until finds the correct one, and returning its index.

I don't know why this has been excluded from the public API, but it's one more point against using Sparse*** anything in my opinion. They're often too basic to be useful for my requirements.

PPartisan
  • 8,173
  • 4
  • 29
  • 48