## 04/22/2004: Java; Caching Short Objects

While looking at the POI source code, I noticed that a lot of Short objects were being created. So I looked around for a small stand-alone class that would allow me to cache Short object. I did see some pages devoted to sparse arrays and matrixes (notably the COLT package) however they were too large for my purposes.

I wrote the `shortShortCache` class shown below. It usage should be pretty obvious but please contact me if you have any difficulty using the class or suggestions for improvement.

```/**
* Provides a cache for Short objects. This class should be used when the same short values
* are used over and over to avoid the cost of continously creating the same Short objects.
*
* Since the get() method creates Short objects and adds them to the cache, the put()
* method never needs to be called outside this class.
*/

public class shortShortCache {

/** This is how the cache is used. */
public static void main(String[] args) {
shortShortCache ssm = new shortShortCache();
short numEntries = (short) 2000;
short start = (short) 23454;
short middle = (short) (start + (numEntries / 2));
short end = (short) (start + numEntries);
for (short i = start; i <= end; i++) {
ssm.put(i);
}
// is the first short cached?
System.out.println(start + ": " + ssm.get(start));
// is the middle short cached?.
System.out.println(middle + ": " + ssm.get(middle));
// is the last short cached?
System.out.println(end + ": " + ssm.get(end));
System.out.println("Done.");
}

/** The initalize size of the cache. */
private int   initialSize     = 500;

/** How much to grow the cache when its capacity is reached. */
private int   increment       = 500;

/** The size of the cache, which is not the same as the number of entries in the caceh. */
private int   currentCapacity = 0;

/**
* The number of entries in the cache.
*/
protected int distinct        = 0;

/** The maximum number of entries so that the cache doesn't grow unbounded. */
protected int maxEntries      = 3000;

/**
* The cached short values.
*/
private short table[];

/**
* The cached Short methods
*/
private Short values[];

/** A no-args constructor which uses all of the defaults. */
public shortShortCache() {
super();
clear();
}

/** A constructor that lets the user set the control variables. */
public shortShortCache(final int _initialSize, final int _increment, final int _maxEntries) {
super();
this.initialSize = _initialSize;
this.increment = _increment;
// we quietly handle the error of a _maxEntries parameter less than the _initialSize parameter.
if (_maxEntries < _initialSize) {
this.maxEntries = _initialSize;
} else if (_maxEntries > Short.MAX_VALUE) {
this.maxEntries = Short.MAX_VALUE;
} else {
this.maxEntries = _maxEntries;
}
clear();
}

/** Create and/or clear the cache. */
public void clear() {
this.table = new short[this.initialSize];
this.values = new Short[this.initialSize];
this.currentCapacity = this.initialSize;
this.distinct = 0;
}

/**
* Returns the value to which this map maps the specified key. If the short value
* is not in the cache, then create a Short object automatically.
*/
public Short get(short key) {
Short rv = null;

for (int i = 0; i < this.distinct; i++) {
if (this.table[i] == key) {
rv = this.values[i];

}
}

// If the key is not in the cache, then add it
// to the cache.
if (rv == null) {
rv = new Short(key);
if (this.currentCapacity < this.maxEntries) {
put(key);
}
}

return rv;
}

/**
* Add a mapping from a short to a Short object.
*
* If the size of the cache is too small, then expand it. If the size of the cache
* is more than the maxEntries, then return. The get() method automatically
* creates a Short object for any short values not in the cache.
*/
public void put(short key) {
if (this.currentCapacity < this.maxEntries) {
if (this.distinct == this.currentCapacity) {
int newCapacity = this.currentCapacity + this.increment;

// store the current cache.
short oldTable[] = this.table;
Short oldValues[] = this.values;

// create new arrays.
short newTable[] = new short[newCapacity];
Short newValues[] = new Short[newCapacity];

this.table = newTable;
this.values = newValues;

// move info from old table to new table.
for (int i = this.currentCapacity; i-- > 0;) {
newTable[i] = oldTable[i];
newValues[i] = oldValues[i];
}

this.currentCapacity = newCapacity;
}
this.table[this.distinct] = key;
this.values[this.distinct] = new Short(key);
this.distinct++;
}
}

/** Returns the number of key-value mappings in this map. */
public int size() {
return this.distinct;
}

/**
* Returns true if this map contains a mapping for the specified key.
*/
public boolean containsKey(short key) {
boolean rv = false;

for (int i = 0; i < this.distinct; i++) {
if (this.table[i] == key) {
rv = true;
break;
}
}
return rv;
}

/**
* Returns true if this map maps one or more keys to the specified value.
*/
public boolean containsValue(Short value) {
boolean rv = false;

if (value != null) {
for (int i = 0; i < this.distinct; i++) {
if (this.values[i].equals(value)) {
rv = true;
break;
}
}
}
return rv;
}

/**
* Returns true if this map contains no key-value mappings.
*/
public boolean isEmpty() {
boolean rv = false;
if (this.distinct > 0) {
rv = true;
}
return rv;
}

/**
* From http://www.ftponline.com/javapro/2004_03/online/rule4_03_31_04/:
*
* Java's object cloning mechanism can allow an attacker to manufacture new
* instances of classes that you define�without executing any of the class's
* constructors. Even if your class is not cloneable, the attacker can define a
* subclass of your class, make the subclass implement java.lang.Cloneable,
* and then create new instances of your class by copying the memory images
* of existing objects. By defining this clone method, you will prevent such attacks.
*/
public final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}

/**
* List all short values in the cache.
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("shortShortMap[" + this.distinct + "]: ");
for (int i = 0; i < this.distinct; i++) {
sb.append(this.table[i] + ", ");
}
return sb.toString();
}
}
```
{"ft_lang_label":"__label__en","ft_lang_prob":0.65679526,"math_prob":0.8886241,"size":6128,"snap":"2022-27-2022-33","text_gpt3_token_len":1501,"char_repetition_ratio":0.15104507,"word_repetition_ratio":0.09144543,"special_character_ratio":0.2935705,"punctuation_ratio":0.18531781,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.95764387,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2022-08-08T13:00:48Z\",\"WARC-Record-ID\":\"<urn:uuid:61c3be98-957e-4f79-8643-a1c0d29479ef>\",\"Content-Length\":\"22042\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:71c21e01-755c-4503-9e93-f1aa20384ed7>\",\"WARC-Concurrent-To\":\"<urn:uuid:410ab981-ed12-46f0-9ec0-dbc875554207>\",\"WARC-IP-Address\":\"185.199.110.153\",\"WARC-Target-URI\":\"https://medined.github.io/blog/page229/\",\"WARC-Payload-Digest\":\"sha1:EUNLXE5HXDAM4KBSOJKAVCCFNEHWQ5DH\",\"WARC-Block-Digest\":\"sha1:HDKFPIC3SSCXLESDKJZ3X3D5VMNZHGZZ\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2022/CC-MAIN-2022-33/CC-MAIN-2022-33_segments_1659882570827.41_warc_CC-MAIN-20220808122331-20220808152331-00518.warc.gz\"}"}