2

So, I'm supposed to use SparseArray instead of HashMap for the sake of performance:

However, SparseArray isn't a part of JCF and does not implement Collection nor List nor Map. HashMap, on the other hand, implements Map and provides values() that I can work with when needing JCF-compatible behavior. For example, using it in an ArrayAdapter and various custom sorting (for values).

My question is three-fold:

  1. Why doesn't SparseArray implement JCF interfaces? I mean, what is the motivation for not implementing these interfaces in light of the fact that most of the methods are already there?
  2. Are there alternatives to SparseArray that implement JCF interfaces or can easily be converted and retain the SparseArray performance?
  3. Are HashMaps with a few hundred elements really that much slower? Are my users really going to notice?

I'm looking for answers with depth and I prefer to have references to authoritative sites. If you think you know why SparseArray was not implemented with JCF interfaces, show some support, help me understand. If you think I should be using SparseArray, show me how to use it with ArrayAdapter and custom sorting (Comparator-esque solutions preferred). If there are better alternatives, links to the API doc, library or tutorial would be helpful. If you think I should stick with HashMaps, explain why the performance benefit of SparseArray is outweighed by the needs of the interfaces.

mawcsco
  • 624
  • 6
  • 18
  • "Are HashMaps with a few hundred elements really that much slower? Are my users really going to notice?" -- when you created your benchmark and ran your tests, particularly using tools like Traceview, what did you learn? – CommonsWare Apr 23 '13 at 15:02
  • 1
    @CommonsWare I never "created a benchmark." Why on earth would I do that? I'm building an app, not testing collections performance. I've run Traceview, but I have no point of reference to say, "this is bad" or "this is good." Everything is running fine. I have nothing to compare it to because I never built it with SparseArray. In fact, there's no practical way to do that. All I have to go on is Lint warnings telling me I should be using SparseArray. Do I ignore those warnings? Do I invest the time to completely refactor my code? – mawcsco Apr 23 '13 at 15:26
  • "Why on earth would I do that?" -- to answer the questions: "Are HashMaps with a few hundred elements really that much slower? Are my users really going to notice?" Nobody else is going to be able to answer that, since we have no idea how, where, and when you are using `HashMap`. "In fact, there's no practical way to do that" -- since you are the only person on the planet who knows your app, we will have to take that at face value. "Do I ignore those warnings?" -- if "there no practical way" to use `SparseArray`, you would appear to have no choice. – CommonsWare Apr 23 '13 at 15:32
  • @CommonsWare Building a benchmark suggests I have some point of reference to compare to. I don't have that. I'm not using SparseArray, because I need to use this data with an ArrayAdapter and I need a custom sort (currently implemented with a Comparator and Collections.sort()). So, my original question is "why" is SparseArray implemented that way. And, since it is, how do I cope with this Lint warning. – mawcsco Apr 23 '13 at 15:41
  • 1
    Then how would you expect anyone to be able to answer question #3? If *you* don't know what they are "that much slower" than, how can we? – CommonsWare Apr 23 '13 at 15:55
  • 1
    If you (collectively) can't answer #3, then why is it recommended? Clearly, somebody knows that SparseArray is a better performing collection. Clearly, somebody has data, from repeated exposure to the problem that they can say with confidence that I should be using SparseArray. Clearly, they added the recommendation to the Lint Rules in the ADK. The only data I've found is too vague to determine if that performance gains will affect small collections. I want an authoritative answer from someone with lots of exposure to SparseArray to help me find more/better data before I make a big decision. – mawcsco Apr 23 '13 at 16:26
  • "If you (collectively) can't answer #3, then why is it recommended?" -- it is suggested by Lint as something you might consider. Lint is not an AI engine; some of the recommendations it makes will be inappropriate for your specific situation. "I want an authoritative answer from someone with lots of exposure to SparseArray to help me find more/better data before I make a big decision" -- you got it, in the comment from fadden (an engineer on Android). – CommonsWare Apr 23 '13 at 16:39
  • If you have `HashMap`, *consider* `SparseArray`. If it is going to be painful to use, use Traceview to determine how much time you are taking up with your present `HashMap`-based solution. If the answer is "not much", then by definition `SparseArray` will help "less than not much", and it's not worth worrying about. With regards to the Lint warning, if you decide to stick with `HashMap`, there should be a `@SuppressLint` annotation that will block the warning. If you are using Eclipse, this annotation should be in the quick-fix list (if not, that's an ADT bug). – CommonsWare Apr 23 '13 at 16:41
  • Performance-wise, it's also useful to think about the additional allocations likely required by boxed ints. There's a really neat presentation by a couple of IBM guys here: http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf – fadden Apr 23 '13 at 17:09

2 Answers2

3

The first version of SparseArray.java was written in May 2006. In some ways it pre-dates the various collection interfaces you're referring to (within Android, not Java). My sense is that it doesn't support the various JCF interfaces because they didn't exist at the time the code was written, and nobody has found reason to add them since. (It didn't even use generics until early 2007.)

If you would find an enhanced SparseArray useful, high-quality patches are always welcome.

fadden
  • 51,356
  • 5
  • 116
  • 166
1

Maybe because it's Map < Object, Object > but SparseArray has primitive keys.

Alternative is Map as it was before

For 3, in general, yes, but one should measure and see if it's true in his case

Alexander Kulyakhtin
  • 47,782
  • 38
  • 107
  • 158
  • Does the auto-unboxing of Map degrade the performance? What about the List interface? – mawcsco Apr 19 '13 at 18:34
  • In Java Puzzlers http://www.amazon.com/Java-Puzzlers-Traps-Pitfalls-Corner/dp/032133678X, if I'm not mistaken, it's explained that boxing-unboxing does hit performance a lot. I might be very wrong on that but better check – Alexander Kulyakhtin Apr 19 '13 at 19:09
  • Can you elaborate on your answer more? #1 I'd like to know more than "maybe" (I can guess on "maybe" too). I'm looking for solid reasons why JCF was not implemented. #2 I'm looking for alternatives beside the solution I already have. #3 I can't switch to SparseArray without completely rewriting a large portion of my code, so I have no practical way to "measure" it. All I've found on the subject is the one article I've linked to. I need more information, not more conjecture. – mawcsco Apr 22 '13 at 13:57
  • 2
    There's no "maybe". It's spelled out in the docs: "It is intended to be more efficient than using a HashMap to map Integers to Objects." Avoiding the constant boxing and unboxing of Integer is the reason for its existence. FWIW, the other fun part about SparseArray is that it implements Cloneable, but its clone() doesn't return Object, making it a covariant method rather than an overload. – fadden Apr 23 '13 at 14:48
  • @fadden "Avoiding the constant boxing and unboxing of Integer is the reason for its existence." That isn't entirely clear to me. However, assuming it's true, that only explains why it doesn't implement Map. What about Collection (or any valid sub-interface), where E is the value type? – mawcsco Apr 23 '13 at 15:44
  • @mawcsco: `Collection` requires an `add()` method taking a single value. `SparseArray` requires keys. – CommonsWare Apr 23 '13 at 15:55
  • @CommonsWare the JCF guide allows for some methods to not be implemented. From the Collection API doc: "...the methods that modify the collection on which they operate, are specified to throw UnsupportedOperationException if this collection does not support the operation." – mawcsco Apr 23 '13 at 16:38
  • @mawcsco: The first version of SparseArray.java was written in May 2006. In some ways it pre-dates the various collection interfaces you're referring to (within Android, not Java). My sense is that it doesn't support the various JCF interfaces because they didn't exist at the time the code was written, and nobody has found reason to add them since. (It didn't even use generics until early 2007.) If you would find it useful, high-quality patches are always welcome. – fadden Apr 23 '13 at 17:03
  • @fadden That is outstanding information. Could you put that in an answer instead of a comment. I'll mark that as an answer. – mawcsco Apr 23 '13 at 17:05