おはようございます。
今回は、
java 8 gold資格試験の出題範囲からジェネリクスとコレクションについて解説します!
はじめに
【対象者】本記事は、Oracle Certified Java Programmer, Gold SE 8 認定資格試験の出題分野の解説をいたします。特に以下のような方には読んでいただければ幸いです。
- 当該試験を受ける方
- java 11 Goldの試験を受ける方で日付/時刻APIの理解を深めたい方
- 受験の有無にかかわらず、javaの日付/時刻APIをおさらいしたい方
- 普通にド忘れしたプログラマーの方
出題範囲の確認
公式ページの出題内容は以下の通りです。
- ジェネリクスクラスを作成および使用する
- ArrayList、TreeSet、TreeMap および ArrayDeque オブジェクトを作成および使用する
- java.util.Comparator およびjava.lang.Comparable インタフェースを使用する
参考(https://education.oracle.com/ja/java-se-8-programmer-ii/pexam_1Z0-809)
前回は上記の項目をまず読み解くのに必要なクラスの一部を紹介しました。
今回も引き続き残りのクラスを解説するとともに、上記の内容の意味するところを読み解いていければと思います!
なので、今回は
- 基礎と簡単なクラス(前半)
- 応用的なクラス(後半)
という流れで進めていきましょう!
それでは、内容をどうぞ。
内容
java.util.Queueとjava.util.Dequeue
【概要】
Queue<E>インタフェースは、「キュー構造」でデータを保持しておくためのインタフェースです。 情報系の方は知っていると思いますが、キュー構造とは図のような最初に入ってきたものを最初に出す、 FIFOという仕組みです。
![](https://java-learner.tokyo/wp-content/uploads/2020/06/queue-1024x425.png)
Deque<E>
java.util.Deque<E>インタフェースもそのサブインタフェースであり、 これを実装するクラスは、図のようにキューの両端でデータを操作するようなメソッドを持つことになります。
![](https://java-learner.tokyo/wp-content/uploads/2020/06/dequeinterface-1024x485.png)
色々な実装クラスがありますが、主なクラスは以下のようなものです。
![](https://java-learner.tokyo/wp-content/uploads/2020/06/deque-1-1024x704.png)
ArrayDeque<E>
クラスのArrayDeque<E>では、内部で配列を使用した上記インタフェースの実装をしています。
このクラスはスレッドセーフなものではありません。マルチスレッドのアプリケーションを作る場合には、 本クラスやLinkedListではなく、Stackクラスを使った方が安全となるようです。
そして、nullを格納することはできません。List系クラスであればnullの格納は一応可能なので、ここが違いとなります。
また、速度に関する特徴としては、
FIFOの動作を行わせる場合に、同様の動作を行うLinkedList<E>がありますが、Dequeの方が高速です。また、 FILOの動作を行わせる場合に、同様の動作を行うStack<E>がありますが、Dequeの方が高速です。
java.util.Set系
【概要】
まず、セットの考え方として、Listなどとは違って、「重複要素を持たない」という特徴があります。 ちなみに、重複要素かどうかを判断する基準に使われているのはequals()メソッドです。 つまり、equalsメソッドを正しくオーバーライドしていないクラスのインスタンスでは、このSetを用いた動作自体がうまくいかない場合があります。
また、nullも重複カウントはありますが、1つなら入れることができます。
そして、treeSetクラスでは順序を保証しますが、各要素に順序性の概念はありません。つまり、拡張for文などを用いて要素を取り出すような操作の場合、取り出されてくる順番はランダムになります。
Set<E>
Setが持つメソッドには以下のようなものがあります。
宣言 | 動作 |
boolean add(E o) | 引数として指定したものをセットに追加します。 |
boolean addAll(Collection<? Extends E> c) | 引数として指定したコレクションの要素を全てセットに追加します。 |
void clear() | 要素を全て削除します。 |
boolean contains(Object o) | 指定された要素を持っている場合はtrueを返します。 |
boolean containsAll(Collection<?> c) | 指定されたコレクションが持つ要素を持っている場合はtrueを返します。 |
boolean isEmpty() | 要素がない場合trueを返します。 |
boolean removeAll(Collection<?> c) | 引数に指定したコレクションが持っている要素をセットから全て削除します。 |
boolean remove(Object o) | 指定されたセットの要素を削除します。 |
int size() | セットの要素数を返します。 |
HashSet<E>
要素の管理にハッシュコードを用いたハッシュテーブルを用いており、上記の特徴通り順番等はとくに保証していません。
Setを直接implementsしています。
TreeSet<E>
木構造に基づいて要素の並びを管理するもので、最初の概要のところからは外れますが、要素には順序付けが行われるため、拡張for文等で取り出す順番は一意になります。
少し段階が多いですが、TreeSetクラスはNavigableSet,NavigableSetはSortedSet,SortedSetはSetをimplementsしている形となります。
java.util.Map系
【概要】
重複しないキーと、一対一で対応づけられたバリューの組み合わせで一つのデータとし、それを複数保持することができる仕組みです。
Go言語のmapや、pythonのディクショナリにあたる機能で(javaにもディクショナリはありますが、古いので今は使われていません)、拡張for文でデータを取り出しつつ用いるには少しメソッド、別インタフェースを噛ませてあげる必要があります。
結構使うところなので、是非覚えておきましょう。
Map<K,V>
主要メソッドは下記の通りです。
ちなみに、Mapはコレクションフレームワークの一旦を担いながら、Collection<E>を継承しているわけではないようです。
メソッド | 動作 |
void clear() | 要素をすべて削除 |
boolean containsKey(Object key) | 指定した値を持つキーが存在する場合true |
boolean containsValue(Object value) | 指定した値を持つバリューが存在する場合true |
Set<Map.Entry<K,V>> entrySet() | マップに含まれる要素をEntryオブジェクトに内包して、要素ひとつひとつに対するEntryオブジェクトを要素とするSetを返す |
V get(Object Key) | 指定したキーに紐づいたバリューを返す |
boolean isEmpty() | 要素がない場合はtrue |
Set<K> keySet() | マップの要素のキーのみで構成されたSetを返す |
V put(K key,V value) | 引数指定したキーとバリューの関係で表される組み合わせのデータをマップに格納する。 |
void putAll(Map<? extends K,? extends V> m) | 引数指定したマップの要素をすべてマップに格納する。 |
V remove(Object o) | 引数指定したキーに紐づいたデータを削除する |
int size() | 要素数を返す。 |
Collection<V> values() | マップの要素のバリューのみで構成されたコレクションインスタンスを返す。 |
HashMap<K,V>
マップの特性を持った上で、上記のHashSetに近い動作をするものです。
近しい関係のクラスに、HashTable<K,V>やLinkedHashMap<K,V>があります。
TreeMap<K,V>
マップの特性を持った上で、上記のTreeSetに近い動作をするものです。
Map.Entry<K,V>
上記メソッドの中で出てきましたが、Mapオブジェクトに格納された要素の1つ1つを表現するためのインタフェースです。
Entryオブジェクトからキーを取り出したい場合は、getKey(),バリューを取り出したい場合はgetValue()メソッドを使えば返り値として取得できます。
つまり、主に拡張for文を用いる際には、以下のようにメソッドを使い分ければいいことになります。
- keyのみで回せる場合はkeySet()
- valueのみで回せる場合はvalues()
- keyもvalueも使って回したい場合にはentrySet()
java.lang.Comparableとjava.util.Comparator
【概要】
オブジェクトの比較と順序づけ(sortと名前のつくようなメソッドでよく使われます)
Comparable
本インタフェースを実装するクラスは、自身のインスタンスと他のインスタンスを比較することができる、そういったオブジェクトになります。
ここで大事なのが、本インタフェースの中で最も重要なメソッドである
int compareTo(T o) を実装していないクラスのインスタンスを
TreeSetの要素 TreeMapのキー など順序づけをサポートするコレクションに格納しようとすると、ClassCastExceptionがスローされます。
そのため、順序づけをサポートしたコレクションへの要素格納時は、
- Comparable<T>をimplementsすること
- compareToを実装すること
が必須条件となります。
compareToの実装の仕方ですが、
- 自オブジェクトと等しいと判断した場合には0を、
- 自オブジェクトの方が大きいと判断した場合には正のint(主に1)
- 自オブジェクトの方が小さいと判断した場合には負のint(主に-1)
を返すように作りましょう。
Comparator
本インタフェースを実装するクラスは、引数などに入る複数のインスタンスを比較してあげることのできる、
いわばユーティリティクラスのような働きをできるようになります。
実装の際の返り値のルールに関しては、Comparableと同じです。
このインタフェースがなぜ使われるか?使い道はあるのか?Comparableの説明を見た方は思うかもしれませんが、ちゃんと意味があってこのインタフェースがあります。
Comparatorの利用ケースとしては、
「元のオブジェクトで順序付けのルールがComparable<T>のcompareToメソッドで決まっているが、それとは異なる順序付けルールでコレクションを管理したい」
と言う場合が考えられます。
上記のTreeSet,TreeMapでは無引数コンストラクタの他に、下記のようなコンストラクタを持っています。
メソッド | 動作 |
Treeset(Comparator<? super E>> | デフォルトのcompareToでなく、指定したComparatorのルールに基づいて順序付けが行われるTreeSetを返す |
TreeMap(Comparator<? super K>) | デフォルトのcompareToでなく、指定したComparatorのルールに基づいてキーの順序付けが行われるTreeMapを返す |
これらのコンストラクタで作成したインスタンスを用いることで、宣言時に指定した並び替えルールにできます。
ちなみに、使用例として、以下のように匿名クラスを噛ませてやると便利なようです。
Set<String> testSet = new TreeSet<>(new Comparator<String>() { public int comparator(String first , String second){ return first.length() - second.length(); } });
まとめ
今回はjava 8 Gold試験対策として、ジェネリクスとコレクションの分野について解説しました。
一度では理解しにくい点も多いと思いますので、読み返したり、実際に手を動かして知識の定着を図っていただければと思います!
それでは、次回またお会いしましょう〜。
コメント