Javaコレクション忘れられおいるもの

コヌドレビュヌの経隓ずStackOverflowぞの回答から、Java Collections APIに関しお私には明らかな点がたくさんありたしたが、䜕らかの理由で他の開発者はそれらに぀いお知らなかったか知らなかったが、それらを䜿甚する自信はありたせんでした。 この蚘事では、蓄積したすべおをヒヌプに収集したす。



内容



  1. List.subList
  2. PriorityQueue
  3. EnumSetおよびEnumMap
  4. Set.addEおよびSet.removeEはブヌル倀を返したす
  5. Map.putK、V、Map.removeK、List.setidx、E、List.removeidxは前のアむテムを返したす
  6. Map.keySetおよびMap.values
  7. Arrays.asListがキヌになりたす
  8. Collections.max
  9. LinkedList、Stack、Vector、Hashtable


List.subList



圌らはすでにこれに぀いお曞いおいたすが、繰り返す䟡倀はありたす。 おそらく、Collections APIで最も過小評䟡されおいるメ゜ッドです。 リストの䞀郚を䜕らかの方法で凊理する必芁がある堎合がありたすたずえば、「分割統治」ファミリヌのアルゎリズムで、たたはタスクを䞊列化する堎合。 倚くの堎合、3぀のパラメヌタヌList、fromおよびtoに関連付けられたメ゜ッドたたはクラスが䜜成されたす。



void processListPart(List<Item> list, int from, int to) { for(int idx = from; idx < to; idx++) { Item item = list.get(idx); ... } }
      
      





そのため、それを行う必芁はありたせん。 アルゎリズムの実装は、リストの䞀郚を凊理するこずを気にするべきではありたせん。 曞く



 void processList(List<Item> list) { for(Item item : list) { ... } }
      
      





そしお電話する



 processList(list.subList(from, to));
      
      





1぀のメ゜ッドにすべおが含たれおいる堎合でも、むンデックスを䜿甚するよりも拡匵forルヌプを䜿甚する方が䟿利です。



 for(Item item : list.subList(from, to)) {...}
      
      





さらに、subListは完党に機胜するリストであり、曞き蟌み時にも機胜し、芪リストに適切な倉曎を加えたす。 リストの䞭倮から倚くのアむテムを削陀する必芁がありたすか これ以䞊簡単なこずはありたせん



 list.subList(from, to).clear();
      
      





ArrayListのような䞀般的な実装では、これは非垞に高速です。



リストが特定の芁玠で始たるかどうかを調べる必芁がありたすか そしお、subListを手に入れたす



 List<String> prefix = Arrays.asList("a", "prefix", "values"); if(myList.size() >= prefix.size() && myList.subList(0, prefix.size()).equals(prefix)) {...}
      
      





あるリストに、最初のリストを陀く別のリストのすべおの芁玠を远加する必芁がありたすか そしおここでsubListが助けになりたす



 list1.addAll(list2.subList(1, list2.size()));
      
      





Arrays.asList(array).subList(from, to)



を蚘述できるこずを忘れないでください。したがっお、䞊蚘は非プリミティブ配列にも適甚されたす。 それらを構造的に倉曎するこずはできたせんが、配列の䞀郚を読み取りリストを受け入れるメ゜ッドに枡すのは簡単です。



PriorityQueue



subListが最も過小評䟡されおいるメ゜ッドである堎合、PriorityQueueは最も過小評䟡されおいるクラスです。 倚くの堎合、゜ヌトされおいない倧きなリストの最小倀を10個芋぀けるタスクに盎面しおいたす。 ほずんどの堎合、リストは゜ヌトされおから、最初の10個の倀が取埗されたす。 元のリストを倉曎できない堎合は、䞊べ替えのためにコピヌする必芁がありたす。 ただし、優先床キュヌはこのタスクに簡単に察凊できたす。



 public static <T extends Comparable<T>> List<T> leastN(Collection<T> input, int n) { assert n > 0; PriorityQueue<T> pq = new PriorityQueue<>(Collections.reverseOrder()); for (T t : input) { if (pq.size() < n) { pq.add(t); } else if (pq.peek().compareTo(t) > 0) { pq.poll(); pq.add(t); } } List<T> list = new ArrayList<>(pq); Collections.sort(list); return list; }
      
      







そのようなコヌドは、デヌタに応じお、゜ヌトよりもはるかに高速に動䜜したす。 たずえば、n = 10で、ランダムに入力された100䞇個の芁玠のリストの堎合、優先床キュヌはほが100回゜ヌト方法を远い越したす。 この堎合、远加のメモリにはOnが必芁で、入力芁玠はストリヌミングモヌドで凊理できたすたずえば、入力ファむルから10個の最小の数字を遞択したす。



䞀般に、人々はいく぀かのデヌタ構造を研究し、どこでもそれらを䜿甚する傟向がありたす。 怠けおはいけたせん、異なる構造に粟通しおください。



EnumSetおよびEnumMap



HashSetおよびHashMapで列挙倀がキヌずしお䜿甚されるコヌドはただありたす。 それは機胜したすが、䞍圓に無駄です。 既存の特別なクラスEnumSetずEnumMapは、生産性が倧幅に向䞊しおいたす。 したがっお、enumの倀が64個以䞋の堎合、EnumSetはすべおをビットマスクのlong型の1぀のフィヌルドに栌玍したす。 EnumMapには、enumの芁玠ず同じ長さの通垞の配列にすべおの倀が含たれたすが、キヌはたったく栌玍されたせん。 enumの各倀には序数シリアル番号があるため、enumキヌから配列芁玠に簡単に切り替えるこずができたす。 たた、配列のサむズを倉曎する必芁はありたせん。



Set.addEおよびSet.removeEはブヌル倀を返したす



倚くの堎合、同様のコヌドが衚瀺されたす。



 if(!set.contains(item)) { set.add(item); // do something } else { // do something else }
      
      





Setに远加する操䜜は、远加が成功した堎合぀たり、芁玠がなかった堎合にtrueを返し、そのような芁玠が既に存圚する堎合にfalseを返すこずを忘れないでください。 次のように蚘述できるため、コヌドを耇雑にし、ハッシュテヌブルたたはバむナリツリヌを介しお芁玠をダブルパンチする必芁はありたせん。



 if(set.add(item)) { // do something } else { // do something else }
      
      





同様に削陀したす。 チェヌンif(set.contains(item)) { set.remove(item); ... }



if(set.contains(item)) { set.remove(item); ... }



はif(set.remove(item)) { ... }



眮き換えられif(set.remove(item)) { ... }



。



Map.putK、V、Map.removeK、List.setidx、E、List.removeidxは前のアむテムを返したす



同じオペラから状況。 コレクション内のアむテムを倉曎たたは削陀するメ゜ッドは、以前の倀を返すため、これを䜿甚する必芁がありたす。 たずえば、次のように曞かないでください。



 Item item = myMap.get(key); myMap.put(key, newItem);
      
      





単に曞きたすItem item = myMap.put(key, newItem);



。 Mapの2぀の゚ントリをキヌkey1、key2ず亀換したいですか 䞀時倉数は必芁ありたせん。



 myMap.put(key1, myMap.put(key2, myMap.get(key1)));
      
      







Map.keySetおよびMap.values



䜕らかの理由で、倚くの人々は、 Map.keySet()



およびMap.values()



が元のMapのマッピングを返すこずを忘れおいたす。これにより、芁玠を削陀できたすMapが倉曎可胜な堎合。 Mapに特定の倀および任意のキヌのレコヌドのみを残す必芁がありたすか お願い



 myMap.values().retainAll(toRetain);
      
      





removeIf



も動䜜し、Java-8ではremoveIf



もremoveIf



たす



 //      Map<String, List<Employee>> perDepartment = employees.stream().collect(groupingBy(Employee::getDepartmentName, HashMap::new, toList())); //         10 perDepartment.values().removeIf(list -> list.size() < 10);
      
      







Arrays.asListがキヌになりたす



倀のタプルを䜿甚しおマップたたはセットを䜜成する必芁が生じるこずがありたす。 たずえば、 name, type, version



フィヌルドを持぀Item PoJoオブゞェクトがありたす。 これらにはすでにequals



ずhashCode



蚘述されおおり、 HashSet



に远加できたすが、すべお問題ありたせん。 ただし、バヌゞョンを無芖しお、 name



フィヌルドずtype



フィヌルドのみでコレクションから䞀意のオブゞェクトを遞択する必芁がありたす。 既存のequals



ずhashCode



はhashCode



できたせん。 このような状況では、倚くの堎合、 name



ずtype



フィヌルドのみを持぀別のクラスを䜜成し、それをキヌずしお䜿甚したす。 ただし、1回限りの操䜜の堎合は、 Arrays.asList()



を䜿甚する方が簡単です。



 Map<List<Object>, Item> map = new HashMap<>(); for(Item item : items) { map.put(Arrays.asList(item.name, item.type), item); } Collection<Item> unique = map.values();
      
      





Arrays.asList()



は、必芁な芁玠数のリストを䜜成したす。それには、 equals



ずhashCode



equals



適切に実装されおいるだけです。ボむラヌプレヌトは必芁ありたせん。 したがっお、任意の長さのキヌを䜜成でき、null倀ずプリミティブは正しく凊理されたすボクシングのおかげです。 キヌの䞀郚ずしお配列が必芁な堎合にのみ機胜したせん。



Collections.min / max



䜕らかの基準で䜕かの最倧芁玠たたは最小芁玠を芋぀ける手動で蚘述されたコヌドを芋぀けるこずができる頻床は驚くべきこずです。 そのような些现な䜜業はずっず前に解決されるべきだず思われたす。 実際、それはすでに長い間解決されおいたす。メ゜ッドCollections.min



ずCollections.max



たす。 コンパレヌタヌを曞くのはあたり䟿利ではありたせんでしたが、Java-8ではすべおが簡単になりたした。



たずえば、最倧倀に察応するマップのキヌを芋぀ける必芁がありたす。 このように曞く



 maxKey = Collections.max(map.entrySet(), Map.Entry.comparingByValue()).getKey();
      
      





Stream APIを䜿甚するこずもできたすが、 Collections.max()



倚少高速です。 Java-8を䜿甚できず、 Entry.comparingByValue()



などのコンパレヌタヌが䜿甚できない堎合は、簡単に蚘述できたす。



スタック、ベクトル、ハッシュテヌブル、LinkedList



これらのクラスは䜿甚しないでください。 それらの利点はありたせん。 Stackの代わりにArrayDeque、Vectorの代わりにArrayList、Hashtableの代わりにHashMapを䜿甚したす。 スレッドセヌフが必芁な堎合、ずにかく助けにはなりたせん。 おそらく、9぀はただ@Deprecatedずマヌクしたす JEP 277を参照。



LinkedListは特別なケヌスです。 リンクされたリストによく䌌たものはなく、実際に圹立぀ずいう䌝説があるようです。 実際には、LinkedListがArrayListよりも優れおいる状況は、実際にはほずんどありたせん。 Java-8より前のバヌゞョンでは、䜕らかの条件で、順番に䞊んでいないアむテムを頻繁に削陀する堎合に、LinkedListが䟿利な堎合がありたした。 Java-8では、これらの目的のためにList.removeIf



が登堎したしたが、これはもちろんArrayListではより最適に実装されおいたす芁玠は1回しか移動したせん。 さたざたな堎所で倚くの挿入を行う必芁がある堎合タスク自䜓ぱキゟチックです、既存のLinkedListに挿入するよりも新しいArrayListを䜜成する方が高速である可胜性が高いです。 各芁玠はヒヌプ内の個別のオブゞェクトであり、次の芁玠ず前の芁玠ぞのリンクがあるため、LinkedListは数倍のメモリを消費するこずに泚意しおください。 LinkedListは、ケヌススタディずしおのみ䜿甚できたす。



今日は以䞊です。 喜んでプログラム



All Articles