6

I need a multi-threaded Map object to use in my web server's caching, and I need to have null keys.

HashMap allows me to have null keys, but ConcurrentHashMap doesn't. I tried to create a synchronized version of HashMap using Collections.synchronizedMap(new HashMap()) but it doesn't accept null keys either.

Is there any alternative that I can use, without having to implement some way to wrap the null keys?

dimo414
  • 47,227
  • 18
  • 148
  • 244
Iravanchi
  • 5,139
  • 9
  • 40
  • 56

2 Answers2

8

The Map returned by Collections.synchronizedMap supports all of the features of the Map you give it. If you give it a HashMap, it supports the null key (and also null values, you said "...I need to have "null" key values..." which can be read either way). What makes you think it doesn't?

This works as expected, for instance:

import java.util.*;

public class MapTest
{
    public static final void main(String[] args)
    {
        Map map;

        try
        {
            map = Collections.synchronizedMap(new HashMap());
            map.put("one", "a");
            System.out.println("Size = " + map.size());
            map.put(null, "b");
            System.out.println("Size = " + map.size());
            System.out.println("map.get(null) = " + map.get(null));
        }
        catch (Exception ex)
        {
            System.out.println("Exception: " + ex.getMessage());
            ex.printStackTrace(System.out);
        }
        System.exit(0);
    }
}

Output:

Size = 1
Size = 2
map.get(null) = b
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Right, my mistake. I mistakenly used a ConcurrentHashMap for my test, instead of a wrapped HashMap. Thanks. – Iravanchi Apr 18 '11 at 07:53
  • @Iravanchi: LOL! Easy to do. Glad that helped, – T.J. Crowder Apr 18 '11 at 08:02
  • This isn't likely a great choice for a server cache. The cache will need to have very high performance, i.e. negligible locking costs. ConcurrentHashMap is much better for this. If you want to allow null values, you can simulate it easily by extending `ConcurrentHashMap` and overriding the `put` method to perform a `remove` when given a null value, after which a `get` for that key will return null, and you still get the much higher concurrency performance. – rees Oct 27 '12 at 04:22
  • Be ware that when using this approach is mandatory to synchronize on the returned map whenever you iterate over the returned collection - see javadoc on `synchronizedMap`. – schneida Jun 15 '20 at 07:22
2

As far as I know there is neither a simple way to make ConcurrentHashMap nor an equivalent class supporting null keys or values.

ConcurrentHashMap is quite different from Collections.synchronizedMap(new HashMap()).

First of all because a synchronized map will prevent any concurrent accesses to happen simultaneously even if all accesses are read only. ConcurrentHashMap won't block concurrent read accesses and, in some cases, may even accept concurrent writes.

But the more important thing is that the Iterators returned by a synchronized map are prone to throw ConcurrentModificationException if the underlying map is modified while using the iterator. On the other hand, the ConcurrentHashMap iterators' are guaranteed to never throw ConcurrentModificationException even if the underlying map is changed while using the iterator.

gabuzo
  • 7,378
  • 4
  • 28
  • 36