[ 
https://issues.apache.org/jira/browse/COLLECTIONS-803?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17705133#comment-17705133
 ] 

Alex Herbert commented on COLLECTIONS-803:
------------------------------------------

This is a case where the implementation in the AbstractHashedMap is not 
optimal. Ideally the {{convertKey}} method should only be invoked once on any 
argument to a public method. Thus the internal {{addMapping}} function should 
have been written to allow passing an already converted key. However there are 
implementations in the library that use this function: {{LRUMap}} overrides the 
method and {{MultiKeyMap}} extensively calls it adding new MultiKey objects. 
Thus changing the behaviour of {{addMapping}} to require {{convertKey}} to be 
called would be a breaking _behavioural_ change and may require modification of 
those classes. Note that the default implementation of {{convertKey}} key 
trivially changes {{null}} to a marker object. Only derived classes that 
override {{convertKey}} will be affected.

The path of least resistance without polluting the API with more methods is to 
reimplement the {{AbstractHashedMap.put}} method in {{CaseInsensitiveMap}} to 
pass the converted key to {{addMapping}} and override the {{createEntry}} 
method to know that the key has already been converted. This override will be a 
_behavioural_ change for any class extending the CaseInsensitiveMap. This is 
not done within the library.

Alternatives are to create new methods to perform this behaviour as private 
(thus not overridable or callable by any child classes), or pollute the API 
with protected methods to perform this behaviour. This will preserve 
functionality of any derived classes that use the existing {{createEntry}} 
method, or {{addMapping}} method.

The decision is to weigh the cost of a _behavioural_ change to derived classes 
(which are outside of this library), verses the performance improvement for all 
users of the CaseInsensitiveMap.

The implementation that hides method implementations privately does not allow 
simple extension. For example a child class that wished to use a decorated 
HashEntry<K, V> to store addition information with each entry would have to 
override the {{put}} method to call a reimplementation of the {{addMapping}} 
function. So I suggest the best approach would be to implement the 
functionality by overriding the minimum of existing methods. I believe this 
would be {{put}} and {{{}createEntry{}}}. These should be documented to be 
overridden to prevent duplicate calls to {{{}convertKey{}}}. The {{addMapping}} 
method would require documentation to indicate that the key is expected to be 
pre-converted by {{{}convertKey{}}}, e.g.
{code:java}
/**
 * {@inheritDoc}
 * 
 * <p>Note: This method should be called with a {@code key} that has been 
pre-converted
 * using {@link #convertKey(Object)}.
 */
@Override
protected void addMapping(int hashIndex, int hashCode, K key, V value) {
    super.addMapping(hashIndex, hashCode, key, value);
}
{code}


> CaseInsensitiveMap prevent duplicate key conversion on put
> ----------------------------------------------------------
>
>                 Key: COLLECTIONS-803
>                 URL: https://issues.apache.org/jira/browse/COLLECTIONS-803
>             Project: Commons Collections
>          Issue Type: Improvement
>          Components: Map
>    Affects Versions: 4.4
>            Reporter: Simulant
>            Priority: Minor
>              Labels: performance
>          Time Spent: 1h 50m
>  Remaining Estimate: 0h
>
> When adding a new item into a {{CaseInsensitiveMap}} the {{convertKey(key)}} 
> method is called twice, once in the {{put(key, value)}} method and second in 
> the {{createEntry(next, hashCode, key, value)}} method. The result could be 
> re-used resulting in a better performance.
> Depending on the {{toString()}} implementation of the key and the resulting 
> length of the key before the lower case conversion the operation can get 
> expensive and should not be called twice, as the {{CaseInsensitiveMap}} 
> overwrites the {{convertKey(key)}} method and makes it more expensive and 
> depending on the input unlike in the implementation of the 
> {{AbstractHashedMap}}.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to