0

While trying to use a LinkedHashMap as a LRU cache, I am facing null pointer exceptions. A similar issue was discussed here, however my scenario is a bit different.

@Override
protected boolean removeEldestEntry(Map.Entry<K, CacheItem<V>> eldest)
{
if(size() >= maxEntriesOnHeap)
{
   if (eldest.getValue() != null && eldest.getValue().isExpired(timeToLiveSecs)) 
   {
   offheap.put(eldest.getKey(), eldest.getValue());
   }
   return true;
}

return false;

}

The entry object is a wrapper object. What I found that if I do not provide the null check, it fails intermittently with the 'eldest' entry encountered having null key and null value. Proper synchronizations are in place.

So, is anyone aware of a scenario when an entry can exist with both key,value as null?

Community
  • 1
  • 1
sutanu dalui
  • 663
  • 7
  • 25

1 Answers1

0

In a simple test case, this seems to work. Maybe you can point out the differences between this test and your implementation?

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashCacheTest
{
    public static void main(String[] args)
    {
        Map<String, CacheItem<Integer>> map = create();

        map.put("K0", new CacheItem<Integer>(0));
        map.put("K1", new CacheItem<Integer>(1));
        map.put("K2", new CacheItem<Integer>(2));
        map.put("K3", new CacheItem<Integer>(3));
        map.put("K4", new CacheItem<Integer>(4));
        map.put("K5", new CacheItem<Integer>(5));
    }

    static class CacheItem<V>
    {
        V v;
        CacheItem(V v)
        {
            this.v = v;
        }
        public boolean isExpired(double timeToLiveSecs)
        {
            return false;
        }
        @Override
        public String toString()
        {
            return String.valueOf(v);
        }
    }

    static <K, V> Map<K, CacheItem<V>> create()
    {
        Map<K, CacheItem<V>> map = new LinkedHashMap<K, CacheItem<V>>()
        {
            @Override
            protected boolean removeEldestEntry(Map.Entry<K, CacheItem<V>> eldest)
            {
                int maxEntriesOnHeap = 5;
                double timeToLiveSecs = 2;
                if(size() >= maxEntriesOnHeap)
                {
                    System.out.println("Removing   : "+eldest.getKey()+", "+eldest.getValue());
                    if (eldest.getValue().isExpired(timeToLiveSecs)) 
                    {
                        System.out.println("To off-heap: "+eldest.getKey()+", "+eldest.getValue());
                        //offheap.put(eldest.getKey(), eldest.getValue());
                    }
                    return true;
                }

                return false;
            }
        };
        return map;
    }
}

In any case, the question may sound naive, but ... are you sure that there are no null keys used? A statement like

map.put(null, value);

will work in the first place...

Marco13
  • 53,703
  • 9
  • 80
  • 159