HashMapキーとしての大文字小文字を区別しない文字列


178

次の理由により、大文字と小文字を区別しない文字列をHashMapキーとして使用したいと思います。

  • 初期化中に、プログラムはユーザー定義の文字列でHashMapを作成します
  • イベント(私の場合はネットワークトラフィック)を処理しているときに、別のケースでStringを受け取った可能性がありますが、<key, value>トラフィックから受け取ったケースを無視してfrom HashMap を見つけることができるはずです。

私はこのアプローチに従いました

CaseInsensitiveString.java

    public final class CaseInsensitiveString {
            private String s;

            public CaseInsensitiveString(String s) {
                            if (s == null)
                            throw new NullPointerException();
                            this.s = s;
            }

            public boolean equals(Object o) {
                            return o instanceof CaseInsensitiveString &&
                            ((CaseInsensitiveString)o).s.equalsIgnoreCase(s);
            }

            private volatile int hashCode = 0;

            public int hashCode() {
                            if (hashCode == 0)
                            hashCode = s.toUpperCase().hashCode();

                            return hashCode;
            }

            public String toString() {
                            return s;
            }
    }

LookupCode.java

    node = nodeMap.get(new CaseInsensitiveString(stringFromEvent.toString()));

このため、すべてのイベントに対してCaseInsensitiveStringの新しいオブジェクトを作成しています。したがって、パフォーマンスに影響する可能性があります。

この問題を解決する他の方法はありますか?


3
[地図持つための良い方法を取得し、ケースを無視入れあり<文字列は、?>?] [1] [1]:stackoverflow.com/questions/212562/...
ボーグランサム

以下の問題についてコメントしましたが、しきい値を下回っているため、他の人には見られない可能性があります。HashMapのサブクラス化に注意してください。JDK8は実装を変更したため、これらの提案を機能させるには、少なくともputAllをオーバーライドする必要があります。
スティーブN

これは正常に動作するはずです。flyweightを使用して、新しいオブジェクトのインスタンス化を取り除くことができます。
topkara

回答:


331
Map<String, String> nodeMap = 
    new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

それだけで十分です。


6
これは、これまでで最も単純であり、繰り返し処理するときにキーの大文字と小文字を保持します。
Ralf

美しいです!これは、ドット表記を使用する機能を維持する、ColdFusionで順序付けられた構造体を作成するためのパズルの最後のピースでした。var struct = {}またはvar struct = structnew()の代わりに、var struct = createObject( 'java'、 'java.util.TreeMap')。init(createObject( 'java'、 'java.lang.String'を使用できます。 ).CASE_INSENSITIVE_ORDER); FUGLY、but it works;)
Eric Fuller

public static <K extends String, V> Map<K, V> caseInsensitiveMap() { return new TreeMap<K, V>(String.CASE_INSENSITIVE_ORDER); }
2015

5
最終版<K extends String>以降Stringは不要: public static <V> Map<String, V> caseInsensitiveMap() { return new TreeMap<String, V>(String.CASE_INSENSITIVE_ORDER); }
Roel Spilker、2015

19
TreeMapは基本的な操作のための一定の時間ではないことに注意してください。ほとんどのアプリケーションでは問題ありませんが、覚えておく価値はあります。JavaDocから:「この実装は、containsKey、get、put、およびremoveオペレーションにlog(n)時間のコストを保証します。アルゴリズムは、Cormen、Leiserson、およびRivestのアルゴリズム入門のアルゴリズムを適応したものです。」
James Schek、2015

57

ここの回答でグイド・ガルシアが示唆したように

import java.util.HashMap;

public class CaseInsensitiveMap extends HashMap<String, String> {

    @Override
    public String put(String key, String value) {
       return super.put(key.toLowerCase(), value);
    }

    // not @Override because that would require the key parameter to be of type Object
    public String get(String key) {
       return super.get(key.toLowerCase());
    }
}

または

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/CaseInsensitiveMap.html


28
contains、putAllなどはどうですか?
アッシリア2012

14
これはトルコ語など一部の言語では機能しません。Googleの「トルコテスト」
Hugo

5
@assylias:true、containsKey()remove()同じ方法でオーバーライドする必要がありますget()HashMap.putAll()実装の用途はput()、そのためには、問題になることはありません-限り、HashMapの実装ステーと同じ。;)また、get()メソッドシグネチャは、Objectではなく、引数として使用しますString。また、コードはnullキーをテストしませんsuper.get(key == null ? null : key.toString().toLowercase());
。– sfera

copy-constructorが必要な場合HashMap(<? extends String, ? extends String> anotherMap)は、同じオペレーションのスーパー実装を呼び出さないでください。その操作では、キーが小文字であることが保証されないためです。super(anotherMap.size()); putAll(anotherMap);代わりに使用できます 。
sfera

マップの値を文字列にしない場合はどうなりますか?(例CaseInsensitiveMap<String, Integer>
アダムパーキン2013年

16

1つのアプローチは、Apache Commons AbstractHashedMapクラスのカスタムサブクラスを作成し、hashおよびisEqualKeysメソッドをオーバーライドして、大文字と小文字を区別しないハッシュとキーの比較を実行することです。(注-私はこれを自分で試したことはありません...)

これにより、マップの検索または更新を行う必要があるたびに新しいオブジェクトを作成するオーバーヘッドが回避されます。そして、一般的なMap操作はO(1)...である必要がありHashMapます。

また、実装の選択を受け入れる準備ができている場合は、Apache Commons CaseInsensitiveMapがカスタマイズ/専門化の作業をAbstractHashedMap行います。


ただし、O(logN)getput操作が許容できるTreeMap場合は、大文字と小文字を区別しない文字列コンパレータを使用したオプションがオプションです。例えばString.CASE_INSENSITIVE_ORDER

putまたはget、またはを実行するたびに新しい一時的なStringオブジェクトを作成してもかまわない場合は、Vishalの答えで十分です。(ただし、そうした場合、キーの元のケースが保持されないことに注意してください...)


6

and (およびおそらく他のキー指向のメソッド)のキーHashMapを小文字にするバージョンをサブクラス化して作成します。putget

または、a HashMapを新しいクラスに合成し、すべてをマップに委任しますが、キーを変換します。

元のキーを保持する必要がある場合は、デュアルマップを維持するか、値とともに元のキーを保存します。


ルックアップ中にString.toLowerCase()を実行するということですか?
rs

@ user710178 ルックアップ中だけでなく、ストレージ中も。
デイブニュートン

@ user710178ああ、そうです、他の回答が指摘するように、追加の依存関係を気にしなければ、これはすでに存在しています。
デイブニュートン

@StephenCそれがあなたのニーズを満たしているなら、確かに; OPがを指定したHashMapので、それが私が行ったものです:)ああ、あなたはコモンズのものを意味します。そうですか。汎用化する必要がない限り(または、最終的にジェネリックになったのでしょうか?)
Dave Newton、

1
JDK 8以降では、実装が変更されたため、(少なくとも)putAllをオーバーライドする必要があります。
スティーブN

4

2つの選択肢が思い浮かびます。

  1. s.toUpperCase().hashCode();のキーとして直接使用できますMap
  2. ケースを無視TreeMap<String>するカスタムでComparatorを使用できます。

そうでなければ、あなたがあなたの解決策を好むなら、新しい種類の文字列を定義する代わりに、必要な大文字小文字の区別機能を備えた新しいマップを実装したいと思います。


3

hashCodeを記憶するためには、文字列を「ラップ」する方が良いでしょう。通常のStringクラスでは、hashCode()は最初はO(N)であり、将来使用するために保持されているため、O(1)です。

public class HashWrap {
    private final String value;
    private final int hash;

    public String get() {
        return value;
    }

    public HashWrap(String value) {
        this.value = value;
        String lc = value.toLowerCase();
        this.hash = lc.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof HashWrap) {
            HashWrap that = (HashWrap) o;
            return value.equalsIgnoreCase(that.value);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return this.hash;
    }

    //might want to implement compare too if you want to use with SortedMaps/Sets.
}

これにより、JavaでのHashtableの実装を使用し、O(1)hasCode()を使用できるようになります。



2

他の回答に基づいて、基本的に2つのアプローチがあります:サブクラス化HashMapまたはラッピングString。最初のものはもう少し作業が必要です。実際、正しく実行したい場合は、ほとんどすべてのメソッドをオーバーライドする必要があります(containsKey, entrySet, get, put, putAll and remove)。

とにかく問題があります。今後の問題を回避LocaleするString場合は、in case操作を指定する必要があります。したがってget(String, Locale)、新しいメソッド(、...)を作成します。すべてが簡単で明確なラッピング文字列です:

public final class CaseInsensitiveString {

    private final String s;

    public CaseInsensitiveString(String s, Locale locale) {
        this.s = s.toUpperCase(locale);
    }

    // equals, hashCode & toString, no need for memoizing hashCode
}

そして、よく、あなたのパフォーマンスの心配について:時期尚早の最適化はすべての悪の根源です :)


2
「そして、パフォーマンスに関する心配について:時期尚早な最適化はすべての悪の根源です:)」-それどころか、それを言い訳として常に非効率的なコードを書くことは悪です。
ゴードン

1
実際、@ Gordonは、コンテキストによってはどちらも同じように悪いです。「悪」というラベルは、「ベストプラクティス」や、多くのIT担当者が使用する傾向のあるその他の役に立たないフレーズのように、白黒の考え方のしるしです。完全に回避するのが最善です。
スティーブンC

「ベストプラクティス」に従っていないことを人々に伝えると、悪い習慣があることを伝えるよりも、掘り起こしが少なくなる傾向があります。
ゴードン

0

これは、最近のプロジェクトで実装したHashMapsのアダプターです。@SandyRと同じように機能しますが、変換ロジックをカプセル化するため、文字列を手動でラッパーオブジェクトに変換しません。

Java 8の機能を使用しましたが、いくつかの変更を加えることで、以前のバージョンに適応させることができます。新しいJava 8ストリーム関数を除いて、ほとんどの一般的なシナリオでテストしました。

基本的には、HashMapをラップし、ラッパーオブジェクトとの間で文字列を変換する際に、すべての関数をそれにマップします。ただし、一部の関数をマップ自体に転送するため、KeySetとEntrySetも調整する必要がありました。したがって、元のkeySet()とentrySet()を実際にラップするキーとエントリの2つの新しいセットを返します。

注:Java 8はputAllメソッドの実装を変更したため、オーバーライドする簡単な方法を見つけることができませんでした。そのため、特に大きなデータセットにputAll()を使用する場合、現在の実装ではパフォーマンスが低下する可能性があります。

バグを見つけた場合、またはコードを改善するための提案がある場合はお知らせください。

パッケージwebbit.collections;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;


public class CaseInsensitiveMapAdapter<T> implements Map<String,T>
{
    private Map<CaseInsensitiveMapKey,T> map;
    private KeySet keySet;
    private EntrySet entrySet;


    public CaseInsensitiveMapAdapter()
    {
    }

    public CaseInsensitiveMapAdapter(Map<String, T> map)
    {
        this.map = getMapImplementation();
        this.putAll(map);
    }

    @Override
    public int size()
    {
        return getMap().size();
    }

    @Override
    public boolean isEmpty()
    {
        return getMap().isEmpty();
    }

    @Override
    public boolean containsKey(Object key)
    {
        return getMap().containsKey(lookupKey(key));
    }

    @Override
    public boolean containsValue(Object value)
    {
        return getMap().containsValue(value);
    }

    @Override
    public T get(Object key)
    {
        return getMap().get(lookupKey(key));
    }

    @Override
    public T put(String key, T value)
    {
        return getMap().put(lookupKey(key), value);
    }

    @Override
    public T remove(Object key)
    {
        return getMap().remove(lookupKey(key));
    }

    /***
     * I completely ignore Java 8 implementation and put one by one.This will be slower.
     */
    @Override
    public void putAll(Map<? extends String, ? extends T> m)
    {
        for (String key : m.keySet()) {
            getMap().put(lookupKey(key),m.get(key));
        }
    }

    @Override
    public void clear()
    {
        getMap().clear();
    }

    @Override
    public Set<String> keySet()
    {
        if (keySet == null)
            keySet = new KeySet(getMap().keySet());
        return keySet;
    }

    @Override
    public Collection<T> values()
    {
        return getMap().values();
    }

    @Override
    public Set<Entry<String, T>> entrySet()
    {
        if (entrySet == null)
            entrySet = new EntrySet(getMap().entrySet());
        return entrySet;
    }

    @Override
    public boolean equals(Object o)
    {
        return getMap().equals(o);
    }

    @Override
    public int hashCode()
    {
        return getMap().hashCode();
    }

    @Override
    public T getOrDefault(Object key, T defaultValue)
    {
        return getMap().getOrDefault(lookupKey(key), defaultValue);
    }

    @Override
    public void forEach(final BiConsumer<? super String, ? super T> action)
    {
        getMap().forEach(new BiConsumer<CaseInsensitiveMapKey, T>()
        {
            @Override
            public void accept(CaseInsensitiveMapKey lookupKey, T t)
            {
                action.accept(lookupKey.key,t);
            }
        });
    }

    @Override
    public void replaceAll(final BiFunction<? super String, ? super T, ? extends T> function)
    {
        getMap().replaceAll(new BiFunction<CaseInsensitiveMapKey, T, T>()
        {
            @Override
            public T apply(CaseInsensitiveMapKey lookupKey, T t)
            {
                return function.apply(lookupKey.key,t);
            }
        });
    }

    @Override
    public T putIfAbsent(String key, T value)
    {
        return getMap().putIfAbsent(lookupKey(key), value);
    }

    @Override
    public boolean remove(Object key, Object value)
    {
        return getMap().remove(lookupKey(key), value);
    }

    @Override
    public boolean replace(String key, T oldValue, T newValue)
    {
        return getMap().replace(lookupKey(key), oldValue, newValue);
    }

    @Override
    public T replace(String key, T value)
    {
        return getMap().replace(lookupKey(key), value);
    }

    @Override
    public T computeIfAbsent(String key, final Function<? super String, ? extends T> mappingFunction)
    {
        return getMap().computeIfAbsent(lookupKey(key), new Function<CaseInsensitiveMapKey, T>()
        {
            @Override
            public T apply(CaseInsensitiveMapKey lookupKey)
            {
                return mappingFunction.apply(lookupKey.key);
            }
        });
    }

    @Override
    public T computeIfPresent(String key, final BiFunction<? super String, ? super T, ? extends T> remappingFunction)
    {
        return getMap().computeIfPresent(lookupKey(key), new BiFunction<CaseInsensitiveMapKey, T, T>()
        {
            @Override
            public T apply(CaseInsensitiveMapKey lookupKey, T t)
            {
                return remappingFunction.apply(lookupKey.key, t);
            }
        });
    }

    @Override
    public T compute(String key, final BiFunction<? super String, ? super T, ? extends T> remappingFunction)
    {
        return getMap().compute(lookupKey(key), new BiFunction<CaseInsensitiveMapKey, T, T>()
        {
            @Override
            public T apply(CaseInsensitiveMapKey lookupKey, T t)
            {
                return remappingFunction.apply(lookupKey.key,t);
            }
        });
    }

    @Override
    public T merge(String key, T value, BiFunction<? super T, ? super T, ? extends T> remappingFunction)
    {
        return getMap().merge(lookupKey(key), value, remappingFunction);
    }

    protected  Map<CaseInsensitiveMapKey,T> getMapImplementation() {
        return new HashMap<>();
    }

    private Map<CaseInsensitiveMapKey,T> getMap() {
        if (map == null)
            map = getMapImplementation();
        return map;
    }

    private CaseInsensitiveMapKey lookupKey(Object key)
    {
        return new CaseInsensitiveMapKey((String)key);
    }

    public class CaseInsensitiveMapKey {
        private String key;
        private String lookupKey;

        public CaseInsensitiveMapKey(String key)
        {
            this.key = key;
            this.lookupKey = key.toUpperCase();
        }

        @Override
        public boolean equals(Object o)
        {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            CaseInsensitiveMapKey that = (CaseInsensitiveMapKey) o;

            return lookupKey.equals(that.lookupKey);

        }

        @Override
        public int hashCode()
        {
            return lookupKey.hashCode();
        }
    }

    private class KeySet implements Set<String> {

        private Set<CaseInsensitiveMapKey> wrapped;

        public KeySet(Set<CaseInsensitiveMapKey> wrapped)
        {
            this.wrapped = wrapped;
        }


        private List<String> keyList() {
            return stream().collect(Collectors.toList());
        }

        private Collection<CaseInsensitiveMapKey> mapCollection(Collection<?> c) {
            return c.stream().map(it -> lookupKey(it)).collect(Collectors.toList());
        }

        @Override
        public int size()
        {
            return wrapped.size();
        }

        @Override
        public boolean isEmpty()
        {
            return wrapped.isEmpty();
        }

        @Override
        public boolean contains(Object o)
        {
            return wrapped.contains(lookupKey(o));
        }

        @Override
        public Iterator<String> iterator()
        {
            return keyList().iterator();
        }

        @Override
        public Object[] toArray()
        {
            return keyList().toArray();
        }

        @Override
        public <T> T[] toArray(T[] a)
        {
            return keyList().toArray(a);
        }

        @Override
        public boolean add(String s)
        {
            return wrapped.add(lookupKey(s));
        }

        @Override
        public boolean remove(Object o)
        {
            return wrapped.remove(lookupKey(o));
        }

        @Override
        public boolean containsAll(Collection<?> c)
        {
            return keyList().containsAll(c);
        }

        @Override
        public boolean addAll(Collection<? extends String> c)
        {
            return wrapped.addAll(mapCollection(c));
        }

        @Override
        public boolean retainAll(Collection<?> c)
        {
            return wrapped.retainAll(mapCollection(c));
        }

        @Override
        public boolean removeAll(Collection<?> c)
        {
            return wrapped.removeAll(mapCollection(c));
        }

        @Override
        public void clear()
        {
            wrapped.clear();
        }

        @Override
        public boolean equals(Object o)
        {
            return wrapped.equals(lookupKey(o));
        }

        @Override
        public int hashCode()
        {
            return wrapped.hashCode();
        }

        @Override
        public Spliterator<String> spliterator()
        {
            return keyList().spliterator();
        }

        @Override
        public boolean removeIf(Predicate<? super String> filter)
        {
            return wrapped.removeIf(new Predicate<CaseInsensitiveMapKey>()
            {
                @Override
                public boolean test(CaseInsensitiveMapKey lookupKey)
                {
                    return filter.test(lookupKey.key);
                }
            });
        }

        @Override
        public Stream<String> stream()
        {
            return wrapped.stream().map(it -> it.key);
        }

        @Override
        public Stream<String> parallelStream()
        {
            return wrapped.stream().map(it -> it.key).parallel();
        }

        @Override
        public void forEach(Consumer<? super String> action)
        {
            wrapped.forEach(new Consumer<CaseInsensitiveMapKey>()
            {
                @Override
                public void accept(CaseInsensitiveMapKey lookupKey)
                {
                    action.accept(lookupKey.key);
                }
            });
        }
    }

    private class EntrySet implements Set<Map.Entry<String,T>> {

        private Set<Entry<CaseInsensitiveMapKey,T>> wrapped;

        public EntrySet(Set<Entry<CaseInsensitiveMapKey,T>> wrapped)
        {
            this.wrapped = wrapped;
        }


        private List<Map.Entry<String,T>> keyList() {
            return stream().collect(Collectors.toList());
        }

        private Collection<Entry<CaseInsensitiveMapKey,T>> mapCollection(Collection<?> c) {
            return c.stream().map(it -> new CaseInsensitiveEntryAdapter((Entry<String,T>)it)).collect(Collectors.toList());
        }

        @Override
        public int size()
        {
            return wrapped.size();
        }

        @Override
        public boolean isEmpty()
        {
            return wrapped.isEmpty();
        }

        @Override
        public boolean contains(Object o)
        {
            return wrapped.contains(lookupKey(o));
        }

        @Override
        public Iterator<Map.Entry<String,T>> iterator()
        {
            return keyList().iterator();
        }

        @Override
        public Object[] toArray()
        {
            return keyList().toArray();
        }

        @Override
        public <T> T[] toArray(T[] a)
        {
            return keyList().toArray(a);
        }

        @Override
        public boolean add(Entry<String,T> s)
        {
            return wrapped.add(null );
        }

        @Override
        public boolean remove(Object o)
        {
            return wrapped.remove(lookupKey(o));
        }

        @Override
        public boolean containsAll(Collection<?> c)
        {
            return keyList().containsAll(c);
        }

        @Override
        public boolean addAll(Collection<? extends Entry<String,T>> c)
        {
            return wrapped.addAll(mapCollection(c));
        }

        @Override
        public boolean retainAll(Collection<?> c)
        {
            return wrapped.retainAll(mapCollection(c));
        }

        @Override
        public boolean removeAll(Collection<?> c)
        {
            return wrapped.removeAll(mapCollection(c));
        }

        @Override
        public void clear()
        {
            wrapped.clear();
        }

        @Override
        public boolean equals(Object o)
        {
            return wrapped.equals(lookupKey(o));
        }

        @Override
        public int hashCode()
        {
            return wrapped.hashCode();
        }

        @Override
        public Spliterator<Entry<String,T>> spliterator()
        {
            return keyList().spliterator();
        }

        @Override
        public boolean removeIf(Predicate<? super Entry<String, T>> filter)
        {
            return wrapped.removeIf(new Predicate<Entry<CaseInsensitiveMapKey, T>>()
            {
                @Override
                public boolean test(Entry<CaseInsensitiveMapKey, T> entry)
                {
                    return filter.test(new FromCaseInsensitiveEntryAdapter(entry));
                }
            });
        }

        @Override
        public Stream<Entry<String,T>> stream()
        {
            return wrapped.stream().map(it -> new Entry<String, T>()
            {
                @Override
                public String getKey()
                {
                    return it.getKey().key;
                }

                @Override
                public T getValue()
                {
                    return it.getValue();
                }

                @Override
                public T setValue(T value)
                {
                    return it.setValue(value);
                }
            });
        }

        @Override
        public Stream<Map.Entry<String,T>> parallelStream()
        {
            return StreamSupport.stream(spliterator(), true);
        }

        @Override
        public void forEach(Consumer<? super Entry<String, T>> action)
        {
            wrapped.forEach(new Consumer<Entry<CaseInsensitiveMapKey, T>>()
            {
                @Override
                public void accept(Entry<CaseInsensitiveMapKey, T> entry)
                {
                    action.accept(new FromCaseInsensitiveEntryAdapter(entry));
                }
            });
        }
    }

    private class EntryAdapter implements Map.Entry<String,T> {
        private Entry<String,T> wrapped;

        public EntryAdapter(Entry<String, T> wrapped)
        {
            this.wrapped = wrapped;
        }

        @Override
        public String getKey()
        {
            return wrapped.getKey();
        }

        @Override
        public T getValue()
        {
            return wrapped.getValue();
        }

        @Override
        public T setValue(T value)
        {
            return wrapped.setValue(value);
        }

        @Override
        public boolean equals(Object o)
        {
            return wrapped.equals(o);
        }

        @Override
        public int hashCode()
        {
            return wrapped.hashCode();
        }


    }

    private class CaseInsensitiveEntryAdapter implements Map.Entry<CaseInsensitiveMapKey,T> {

        private Entry<String,T> wrapped;

        public CaseInsensitiveEntryAdapter(Entry<String, T> wrapped)
        {
            this.wrapped = wrapped;
        }

        @Override
        public CaseInsensitiveMapKey getKey()
        {
            return lookupKey(wrapped.getKey());
        }

        @Override
        public T getValue()
        {
            return wrapped.getValue();
        }

        @Override
        public T setValue(T value)
        {
            return wrapped.setValue(value);
        }
    }

    private class FromCaseInsensitiveEntryAdapter implements Map.Entry<String,T> {

        private Entry<CaseInsensitiveMapKey,T> wrapped;

        public FromCaseInsensitiveEntryAdapter(Entry<CaseInsensitiveMapKey, T> wrapped)
        {
            this.wrapped = wrapped;
        }

        @Override
        public String getKey()
        {
            return wrapped.getKey().key;
        }

        @Override
        public T getValue()
        {
            return wrapped.getValue();
        }

        @Override
        public T setValue(T value)
        {
            return wrapped.setValue(value);
        }
    }


}

0

このため、すべてのイベントに対してCaseInsensitiveStringの新しいオブジェクトを作成しています。したがって、パフォーマンスに影響する可能性があります。

ルックアップの前にラッパーを作成するか、キーを小文字に変換すると、両方とも新しいオブジェクトが作成されます。これを回避する唯一の方法は、独自のjava.util.Map実装を作成することです。それはそれほど難しくなく、IMOはそれだけの価値があります。次のハッシュ関数は、数百キーまでかなりうまく機能することがわかりました。

static int ciHashCode(String string)
{
    // length and the low 5 bits of hashCode() are case insensitive
    return (string.hashCode() & 0x1f)*33 + string.length();
}

-3

Java 8ストリームの使用についてはどうでしょう。

nodeMap.entrySet().stream().filter(x->x.getKey().equalsIgnoreCase(stringfromEven.toString()).collect(Collectors.toList())

これでは、大文字と小文字を区別しない方法でマップ内の値を検索することはできません。
ギリ

equalsignorecaseはそうではありませんか?
アマレンドラレディ

リストを作成しています。OPがマップを要求しました。
ギリ

これは、マップのO(1)複雑さの利点を破壊します。
Paul Rooney
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.