 <p>There is no reason to choose between <code>putIfAbsent</code> and <code>computeIfPresent</code>. Most notably, <code>computeIfPresent</code> in entirely inappropriate as it, as its name suggests, only computes a new value, when there is already an old one, and <code>(k,v)-&gt;v</code> even makes this computation a no-op.</p> <p>There are several options</p> <ol> <li><p><code>containsKey</code>, <code>put</code> and <code>get</code>. This is the most popular pre-Java 8 one, though its the most inefficient of this list, as it incorporates up to three hash lookups for the same key</p> <pre><code>String key=str.substring(i, j); if(!map.containsKey(key)) map.put(key, new HashSet&lt;&gt;()); map.get(key).add(str); </code></pre></li> <li><p><code>get</code> and <code>put</code>. Better than the first one, though it still may incorporate two lookups. For ordinary <code>Map</code>s, this was the best choice before Java 8:</p> <pre><code>String key=str.substring(i, j); Set&lt;String&gt; set=map.get(key); if(set==null) map.put(key, set=new HashSet&lt;&gt;()); set.add(str); </code></pre></li> <li><p><code>putIfAbsent</code>. Before Java 8, this option was only available to <code>ConcurrentMap</code>s.</p> <pre><code>String key=str.substring(i, j); Set&lt;String&gt; set=new HashSet&lt;&gt;(), old=map.putIfAbsent(key, set); (old!=null? old: set).add(str); </code></pre> <p>This only bears one hash lookup, but needs the unconditional creation of a new <code>HashSet</code>, even if we don’t need it. Here, it might be worth to perform a <code>get</code> first to defer the creation, especially when using a <code>ConcurrentMap</code>, as the <code>get</code> can be performed lock-free and may make the subsequent more expensive <code>putIfAbsent</code> unnecessary.</p> <p>On the other hand, it must be emphasized, that this construct is not thread-safe, as the manipulation of the value <code>Set</code> is not guarded by anything.</p></li> <li><p><code>computeIfAbsent</code>. This Java 8 method allows the most concise and most efficient operation:</p> <pre><code>map.computeIfAbsent(str.substring(i, j), k -&gt; new HashSet&lt;&gt;()).add(str); </code></pre> <p>This will only evaluate the function, if there is no old value, and unlike <code>putIfAbsent</code>, this method returns the new value, if there was no old value, in other words, it returns the right <code>Set</code> in either case, so we can directly <code>add</code> to it. Still, the <code>add</code> operation is performed outside the <code>Map</code> operation, so there’s no thread safety, even if the <code>Map</code> is thread safe. But for ordinary <code>Map</code>s, i.e. if thread safety is not a concern, this is the most efficient variant.</p></li> <li><p><code>compute</code>. This Java 8 method will always evaluate the function and can be used in two ways. The first one</p> <pre><code>map.compute(str.substring(i, j), (k,v) -&gt; v==null? new HashSet&lt;&gt;(): v).add(str); </code></pre> <p>is just a more verbose variant of <code>computeIfAbsent</code>. The second</p> <pre><code>map.compute(str.substring(i, j), (k,v) -&gt; { if(v==null) v=new HashSet&lt;&gt;(); v.add(str); return v; }); </code></pre> <p>will perform the <code>Set</code> update under the <code>Map</code>’s thread safety policy, so in case of <code>ConcurrentHashMap</code>, this will be a thread safe update, so using <code>compute</code> instead of <code>computeIfAbsent</code> has a valid use case when thread safety is a concern.</p></li> </ol>