Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

I have a map-like type SmurfMap<K, V> which in certain contexts I use as a set-like SmurfMap<K, Void>. Implementation details forbid the values of the map from being null, so I cannot actually use Void as a unit type. Are there any non-null alternatives to Void in the JCL or Guava?

Types considered and not yet rejected:

  • new singleton enum Unit
  • Class<Void>
  • TypeToken<Void>
  • Object

EDIT SmurfMap<K, V> does not implement java.util.Map. The datastructure backing a SmurfMap is terabytes to petabytes in size.

share|improve this question
1  
Standard Java libraries use Boolean (Set<T> set = Collections.newSetFromMap(Map<T, Boolean> map)) –  Ordous May 26 at 16:19
    
Is K actually an enum? –  MichaelT May 26 at 16:20
    
@Ordous Boolean seems odd. What's the difference between a map which does not contain the key "fish" and a map where the key "fish" go to false? –  Robert Cooper May 26 at 16:26
1  
@RobertCooper The value is never looked at, only the presence or absence of such. Hey, I didn't write java.util, don't blame me for quirky stuff there! –  Ordous May 26 at 16:29
2  
So you're asking what's a suitable way of iterating through the keys of SmurfMap, which doesn't implement java.util.Map and therefore no keySet() to rely on? FWIW java.util.HashSet is backed by java.util.HashMap and uses private static final Object PRESENT = new Object(); as the value. –  h.j.k. May 27 at 6:46

2 Answers 2

If you don't need the values, don't use a map. Use a Set. It's a collection that contains no duplicate elements (by equals and hashCode) and has O(1) membership checking.

If the code is impossible to structure in a way that uses a set, and it must use a map*, then of these options I'd make a singleton Unit type. I'd pick this because as a map value, it does the best job communicating that the value is unused. A Map<T, Boolean> implies that the boolean-ness of the values matters and should be checked.

* This indicates a pretty nasty code smell, and you should examine your design more.

share|improve this answer
2  
I think you have the situation backwards - seems the OP already has a custom Map, and doesn't want to duplicate the code into a almost-identical Set. (Same reason there are no ConcurrentSets in Java). Hence this is not a question of "I want a set, what should I use? I've got a Map.", but rather "I've got this Map, I'd like to reuse the code as a Set, but without copy-pasting". –  Ordous May 26 at 16:54
    
@Ordous I'm still answering the first question - if you have a map that you pass around, and the values are being used, there's no need to even ask the question because you just use map.contains. If you have a map and you never use the values, you shouldn't be using a map. If you have a map, never use the values, and can't replace it with a set, it's a code smell as I said and in that case I recommended the Unit singleton value. I think this pretty solidly answers all aspects of the question. –  Daenyth May 26 at 17:00
    
But then your answer collapses into "Use a Unit type!" with no argument or reason for it. –  Ordous May 26 at 17:04
3  
@Ordous: Hence this is not a question of "I want a set, what should I use? I've got a Map.", but rather "I've got this Map, I'd like to reuse the code as a Set, but without copy-pasting". And the answer is still valid: "don't do that." This looks like a classic case of "when all you have is a hammer..." –  Mason Wheeler May 26 at 20:59
1  
@MasonWheeler ConcurrentSkipListSet<E> is implemented on top of a ConcurrentNavigableMap<E,Object>, HashSet<E> is implemented on top of HashMap<E, Object>. I'm doing something similar. I'd like to avoid the weight of a custom SmufSet<K> interface if it's easy. –  Robert Cooper May 27 at 5:18

Two alternative techniques to consider:

  • Use a type with the Void generic argument removed. Instead of a Callable<Void>, use a Runnable. Instead of a SmurfMap<K, Void>, use (or make) a SmurfSet<K>

  • Modify the clients to be null-friendly. For example, I know of no good alternative to Future<Void>. Guava's Futures.allAsList() returns an unmodifiable wrapped ArrayList, not an ImmutableList, quite possibly in part because a the null-hostile ImmutableList would prevent the method from being called with Future<Void>s.

share|improve this answer
    
Is there any reason why you are proposing some concurrency-related classes in your own answer? If so, are they missing from your original question? –  h.j.k. May 27 at 23:58
1  
My question was "Non-null alternative to Void (Java unit type)". I gave a specific case about a SmurfMap, but my question in general was about what to do you do when you'd like to use Void as a type parameter but you can't use null values. Callable, Runnable, and Future were random examples to illustrate different workarounds. The fact that they are all concurrency related was a coincidence (I could just as easily used Supplier or Function for examples). –  Robert Cooper May 28 at 3:24
    
Ah I see, thanks for the clarification. –  h.j.k. May 28 at 3:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.