<div dir="ltr">update: it has been confirmed to be a bug. </div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Dec 9, 2015 at 12:22 PM, Jaromir Hamala <span dir="ltr"><<a href="mailto:jaromir.hamala@gmail.com" target="_blank">jaromir.hamala@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div style="font-size:12.8px">Hi,</div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">I apologize if this is not the right group to discuss possible issues in JDK8 j.u.c package. Please feel free to point me to a more appropriate group.</div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px"><span style="font-size:12.8px">I stumbled upon an interesting issue with default implementation of `compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)` in JDK8 `ConcurrentMap`.</span><br></div><div style="font-size:12.8px">According to its contract the default method implementation assumes map implementations do not support null values. </div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">This is the begin of the default implementation: <br></div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {</div><div style="font-size:12.8px">        Objects.requireNonNull(remappingFunction);</div><div style="font-size:12.8px">        V oldValue = get(key);</div><div style="font-size:12.8px">        for(;;) {</div><div style="font-size:12.8px">            V newValue = remappingFunction.apply(key, oldValue);</div><div style="font-size:12.8px">            if (newValue == null) {</div><div style="font-size:12.8px">                // delete mapping</div><div style="font-size:12.8px">                if (oldValue != null || containsKey(key)) {</div><div style="font-size:12.8px">                    // something to remove</div><div style="font-size:12.8px">                    if (remove(key, oldValue)) {</div><div style="font-size:12.8px">[...]</div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">Let's say we have an empty map and 2 threads: </div><div style="font-size:12.8px">T1 is calling the `compute('foo', someFunction)`</div><div style="font-size:12.8px">T2 is concurrently calling calling `put('foo', 'bar');`</div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">so the T1 will get `oldValue = null`, but `containsKey()` will return `true` - because T2 already created the mapping `foo -> bar`. Hence T1 will call `remove('foo', null)` !</div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">Contract of `remove()` says: `throws NullPointerException if the specified key or value is null, and this map does not permit null keys or values optional.` -> the T1 will throw NPE.  </div><div style="font-size:12.8px">Is it a bug in default method impl or do I understand it wrong?<br></div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">Cheers,</div><div style="font-size:12.8px">Jaromir</div><span class="HOEnZb"><font color="#888888"><div><br></div>-- <br><div>“Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.”<br>Antoine de Saint Exupéry</div>
</font></span></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">“Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.”<br>Antoine de Saint Exupéry</div>
</div>