What is the SparseArray always warned by intellij?

Source: Internet
Author: User

What is the SparseArray always warned by intellij?

If you only want to see the comparison and conclusion, you can jump to the end.

Preface

As a code-cleaning programmer, when writing Android applications, I always pay attention

  • Code specification (Google Android Guideline)
  • No two lines of code can be written.
  • Never make the scroll bar on the right of the compiler (intellij, as) Yellow
  • Do not repeat yourself

Of course, in actual development, the compiler reports that warning is somewhat difficult to avoid. For example, the compiler does not think there will be null pointers from the android source code, but in actual situations .... You know, if some rom operations break down the source code, the result will be crash, so what we can do is to minimize warning.

After talking about the theme, sometimes intellij idea will report "warning" in the HashMap statement line, saying that SparseArray is better. Why is SparseArray better, why is it suggested to save more memory?

This document uses the source code of api 21 as the standard.

SparseArray source code analysis
// E corresponds to Valuepublic class SparseArray of HashMap <E> implements Cloneable {// used to optimize the deletion performance and mark the DELETED Object private static final Object DELETED = new Object (); // used to optimize the deletion performance and Mark whether garbage collection is required. private boolean mGarbage = false; // storage index. The integer index is mapped to the private int [] mKeys array from small to large; // storage Object private Object [] mValues; // actual size private int mSize;

Constructor:

Public SparseArray (int initialCapacity) {if (initialCapacity = 0) {// EmptyArray is a lightweight representation that does not require array allocation. MKeys = EmptyArray. INT; mValues = EmptyArray. OBJECT;} else {mValues = ArrayUtils. Equals (initialCapacity); mKeys = new int [mValues. length];} mSize = 0 ;}

Memory is also fully saved here. NewUnpaddedObjectArray finally points to a native method of VMRuntime

/*** Returns an array with at least long minLength, but may be larger. The increasing size comes from avoiding any padding after the array. The size of padding depends on componentType and memory distributor implementation */public native Object newUnpaddedArray (Class <?> ComponentType, int minLength );

The Get method uses binary search.

/*** Get the ing object of the specified key, or if null does not have the ing. */Public E get (int key) {return get (key, null) ;}@ SuppressWarnings ("unchecked") public E get (int key, E valueIfKeyNotFound) {// Binary Search int I = ContainerHelpers. binarySearch (mKeys, mSize, key); // if not found or the value has been marked to be DELETED if (I <0 | mValues [I] = DELETED) {return valueIfKeyNotFound;} else {return (E) mValues [I] ;}}

Here we will not go into details about the implementation of the corresponding binary search, which is a circular query that splits an ordered array into two and compares the median and target values.

The clever one is that a ~ is returned when it is not found ~ Low index, which has two functions:

  • The caller is notified that no information is found.
  • Callers can directly use ~ Result: the position where the element should be inserted (-(insertion point)-1 ).

Corresponding put Method

/*** Add a ing between the specified key and the specified object. If there is a key ing between the specified key, the original ing object is replaced directly. */Public void put (int key, E value) {int I = ContainerHelpers. binarySearch (mKeys, mSize, key); if (I> = 0) {// This key was originally available, replacing mValues [I] = value ;} else {// perform a negative operation to obtain the index I = ~ TO BE INSERTED ~ I; // The size is sufficient and the original value has been marked as deleting if (I <mSize & mValues [I] = DELETED) {mKeys [I] = key; mValues [I] = value; return;} // when I arrive here, I exceeds the size, or the corresponding element is valid // marked as needing garbage collection and SparseArray size is not smaller than the length of the keys array if (mGarbage & mSize> = mKeys. length) {// compressed space (here the source code is a bit funny, and there is still a Log. e comments stay there, it seems that the Android source code engineer also needs to debug), will compress the array, Remove invalid values, ensure continuous valid value gc (); // search again because the index may change I = ~ ContainerHelpers. binarySearch (mKeys, mSize, key);} // insert. If the size is not enough, a larger array will be re-allocated, copied and inserted. If the size is enough, System will be used. arraycopy moves the values at the beginning of the insert position behind and then inserts mKeys = GrowingArrayUtils. insert (mKeys, mSize, I, key); mValues = GrowingArrayUtils. insert (mValues, mSize, I, value); // increase the actual size by 1 mSize ++ ;}}

Check the remove (del) method.

/*** If any, delete the key ing of the corresponding key */public void delete (int key) {// It is a binary search int I = ContainerHelpers. binarySearch (mKeys, mSize, key); // if it exists, the corresponding value is marked as DELETED, and the location mGarbage if (I> = 0) {if (mValues [I]! = DELETED) {mValues [I] = DELETED; mGarbage = true ;}}/ *** alias of {@ link # delete (int. */public void remove (int key) {delete (key) ;}/ *** delete the ing of the specified index (this is a bit violent. It should be used less often, directly specified location) */public void removeAt (int index) {// is the method in delete, so why does delete need to repeat this code without calling removeAt? if (mValues [index]! = DELETED) {mValues [index] = DELETED; mGarbage = true ;}}

After reading the methods of crud, we should have a preliminary understanding. SparseArray is because the key is a pure integer array, this avoids ing K/V relationships between auto-boxing keys and additional data structures, thus saving memory.

Of course, there is also a tradeoff here, because the key array needs to be ordered, so each write operation will take more time, to perform binary search, to delete/Insert elements in the array. Therefore, for optimization, because mGarbage and DELETED are used, the possible gc may be merged once, and execution is delayed until necessary.

As mentioned in the source code comment, this class is not suitable for large data volumes. it is acceptable that there are hundreds of entries with a difference of less than 50%. After all, what we lack on mobile terminals is often memory, instead of CPU.

HashMap source code analysis

Compared with SparseArray, the implementation of HashMap is more complex, because it supports multiple keys (or even null) and implements Iterator. Here we mainly look at the basic operation implementation.

/*** The transient keyword indicates that serialization is not required. * Hash table, where the null key is located. * HashMapEntry defines K/V ing, hash value, and next element */transient HashMapEntry <K, V> [] table;/*** this entry represents a null key, or the ing does not exist. */transient HashMapEntry <K, V> entryForNullKey;/*** Number of hash ing hash map. */transient int size;/*** auto-increment during structure modification to perform (maximum effort) concurrent modification detection */transient int modCount; /*** the hash table will be rehash when the size exceeds the threshold value. Generally, this value is 0.75 * capacity unless the capacity is 0, that is, the preceding EMPTY_TABLE statement. */Private transient int threshold; public HashMap (int capacity) {if (capacity <0) {throw new IllegalArgumentException ("Capacity:" + capacity );} if (capacity = 0) {// similar to SparseArray, all EMPTY instances share the same EMPTY, which indicates HashMapEntry <K, V> [] tab = (HashMapEntry <K, v> []) EMPTY_TABLE; table = tab; // force put () to replace EMPTY_TABLE threshold =-1; return;} if (capacity <MINIMUM_CAPACITY) {capacity = MINIMUM_CAPACITY ;} Else if (capacity> MAXIMUM_CAPACITY) {capacity = MAXIMUM_CAPACITY;} else {// is it for memory padding capacity = Collections. roundUpToPowerOfTwo (capacity);} makeTable (capacity);}/*** allocate a hash table based on the given capacity and set the corresponding threshold value. * @ Param newCapacity must be 2 times, because the memory needs to be aligned */private HashMapEntry <K, V> [] makeTable (int newCapacity) {// is this done for synchronization consideration of HashMapEntry <K, V> [] newTable = (HashMapEntry <K, V> []) new HashMapEntry [newCapacity]; table = newTable; threshold = (newCapacity> 1) + (newCapacity> 2); // 3/4 capacity return newTable ;}

Then the inserted code

/*** Ing specifies the key to the specified value. If there is an original mapping, return its value; otherwise, return null. * // @ Override public V put (K key, V value) {if (key = null) {// if the key is null, directly go to the putValueForNullKey method return putValueForNullKey (value );} // calculate the hash value of the key and perform secondary hash int hash = Collections based on the hashCode of the key. secondaryHash (key); HashMapEntry <K, V> [] tab = table; int index = hash & (tab. length-1); for (HashMapEntry <K, V> e = tab [index]; e! = Null; e = e. next) {// the corresponding entry already exists. Modify the value directly and return the oldValue if (e. hash = hash & key. equals (e. key) {preModify (e); V oldValue = e. value; e. value = value; return oldValue; }}// if no existing entry exists, create a modCount ++; // The size exceeds the threshold value, which is the double capacity, re-calculate index if (size ++> threshold) {tab = doubleCapacity (); index = hash & (tab. length-1);} // Insert a new HashMapEntry at the index position of the table. Its next is its own addNewEntry (key, value, hash, index); return null ;} private V putValueForNullKey (V value) {HashMapEntry <K, V> entry = entryForNullKey; // logic similar to the above class. If so, replace it, otherwise, create the HashMapEntry if (entry = null) {addNewEntryForNullKey (value); size ++; modCount ++; return null;} else {preModify (entry ); V oldValue = entry. value; entry. value = value; return oldValue ;}}

Here, we can roughly understand that HashMap is a hash-centered implementation. in size, it only has the double logic, and whether to narrow down the capacity logic without removing it. Time complexity O (1) costs a lot of memory to store data.

Comparison

HashMap-> fast, wasting memory
SparseArray-> performance loss and memory saving

We will conduct a simple performance test, without initializing HashMap and SparseArray with parameters, and store the Integer ing of Integer-> String.

Time used to separate HashMap and SparseArray with the symbol (MS)

Lab First time Second Third time Fourth
Put 10000 entries in sequence 12: 6 76: 4
Random put 10000 count 16: 83 18: 85 15: 76 17: 78

The results of the four tests are similar (there is a noise data of 76/4 to be studied). HashMap consumes more time in the ordered key, while SparseArray consumes more time when no key is needed, hashMap does not have much performance difference.

After 10000 get operations are performed on the random put results, the results of, and are obtained. As shown in the get operation, SparseArray has better performance, however, even when there are 10000 entries, the difference is not big.

In the memory, we can see that SparseArray is 32 in Allocation Tracker, and HashMap reaches 69632, which is a terrible number ......

Conclusion

When the key is an integer, considering that the K/V pair on the Mobile End is usually not too large, SparseArray can be used to save more memory and ensure acceptable performance loss.

From the test results, SparseArray greatly saves memory compared with HashMap, which is the best choice for mobile terminals.

Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.