ドキュメント



JavaFX: JavaFX Collectionsの使用

1 JavaFX Collectionsの使用

このチュートリアルでは、Java Collections Frameworkの拡張であるJavaFX Collections APIについて説明し、コンパイルして実行できるコード・サンプルを提供しています。

このチュートリアルではまず、Java Collections Frameworkの関連クラスおよびインタフェースについて簡単に再確認してから、これらがJavaFX Collections APIでどのように拡張されて追加の動作を提供するかを説明します。Java Collectionsの詳細なチュートリアルは、JavaチュートリアルのCollectionsトレールを参照してください。

Java Collectionsの基本事項の再確認

この項では、java.util.Listjava.util.Mapインタフェースおよびjava.util.Collectionsクラスについて簡単に説明します。Java Collectionsについてすでによく理解している場合は、次の項である「JavaFX Collectionsの学習」に進んでください。

List

Listは順序付けされたオブジェクトのコレクションであり、java.util.Listインタフェースによって表されます。List内のオブジェクトは要素と呼ばれ、同じList内には複数の要素が存在できます。Listインタフェースによって有用な複数のメソッドが定義されており、これにより、要素の追加、特定のインデックスにある要素へのアクセスまたは変更、サブリストの作成、リスト内の要素の検索、リストの消去などを行うことができます。

例1-1に、これらのメソッドをStringオブジェクトのListとともに示します。

例1-1 Listの使用

package collectionsdemo;
 
import java.util.List;
import java.util.ArrayList;
 
public class CollectionsDemo {
 
    public static void main(String[] args) {
 
        // Create a List.
        System.out.println("Creating the List...");
        List<String> list = new ArrayList<String>();
        list.add("String one");
        list.add("String two");
        list.add("String three");
 
        // Print out contents.
        printElements(list);
        
        // Set a new element at index 0.
        System.out.println("Setting an element...");
        list.set(0, "A new String");
        printElements(list);
        
        // Search for the newly added String.
        System.out.println("Searching for content...");
        System.out.print("Contains \"A new String\"? ");
        System.out.println(list.contains("A new String"));
        System.out.println("");
        
        // Create a sublist.
        System.out.println("Creating a sublist...");
        list = list.subList(1,3);
        printElements(list);
        
        // Clear all elements.
        System.out.println("Clearing all elements...");
        list.clear();
        printElements(list);
    }
    
    private static void printElements(List<String> list) {
        System.out.println("Size: "+list.size());
        for (Object o : list) {
            System.out.println(o.toString());
        }
        System.out.println("");
    }
}

例1-1の出力は、次のとおりです。

Creating the List...

Size: 3

String one

String two

String three

Setting an element...

Size: 3

A new String

String two

String three

Searching for content...

Contains "A new String"? true

Creating a sublist...

Size: 2

String two

String three

Clearing all elements...

Size: 0

このプログラムではまず、ArrayList (Listインタフェースの具象実装)がインスタンス化され、list変数に割り当てられます。次に、addメソッドを呼び出すことにより、リストに3つのStringオブジェクトが追加されます。(その実行の様々なポイントで、プログラムにより、printElementsと呼ばれるカスタムprivate staticメソッドを呼び出すことによって要素が出力されます。)行list.set(0,"A new String")によって、最初のインデックス位置にある元のStringオブジェクトが新しいStringオブジェクトと置き換えられます。containsメソッドによって、Listに指定した要素が存在するかどうかがレポートされ、sublistメソッドによって、所定のインデックス値で指定された範囲から新しいListが返されます。最後に、clearメソッドによって、Listからすべての要素が削除されます。

Map

Mapは、キーを値にマップするオブジェクトです。Mapには重複するキーを含めることができません。キーはそれぞれ1つの値にのみマップできます。キーと値をMapに配置し、そのキーを渡すことによって値を取得できます。たとえば、キーappleではfruitが返され、carrotではvegetableが返されます。

例1-2に、これらのメソッドをStringオブジェクトのMapとともに示します。

例1-2 マップの使用

package collectionsdemo;
 
import java.util.Map;
import java.util.HashMap;
 
public class CollectionsDemo {
 
    public static void main(String[] args) {
        
        // Create a Map.
        Map<String,String> map = new HashMap<String,String>();
        map.put("apple", "fruit");
        map.put("carrot","vegetable");
        System.out.println("Size: "+map.size());
        System.out.println("Empty? "+map.isEmpty());
        
        // Pass in keys; print out values.
        System.out.println("Passing in keys and printing out values...");
        System.out.println("Key is apple, value is: "+map.get("apple"));
        System.out.println("Key is carrot, value is: "+map.get("carrot"));
        System.out.println("");
        
        // Check keys and values.
        System.out.println("Inspecting keys and values:");
        System.out.println("Contains key \"apple\"? "+
               map.containsKey("apple"));
        System.out.println("Contains key \"carrot\"? "+
               map.containsKey("carrot"));
        System.out.println("Contains key \"fruit\"? "+
               map.containsKey("fruit"));
        System.out.println("Contains key \"vegetable\"? "+
               map.containsKey("vegetable"));
        System.out.println("Contains value \"apple\"? "+
               map.containsValue("apple"));
        System.out.println("Contains value \"carrot\"? "+
               map.containsValue("carrot"));
        System.out.println("Contains value \"fruit\"? "+
               map.containsValue("fruit"));
        System.out.println("Contains value \"vegetable\"? "+
               map.containsValue("vegetable"));
        System.out.println("");
        
        // Remove objects from the map.
        System.out.println("Removing apple from the map...");
        map.remove("apple");
        System.out.println("Size: "+map.size());
        System.out.println("Contains key \"apple\"? "+
               map.containsKey("apple"));
        System.out.println("Invoking map.clear()...");
        map.clear();
        System.out.println("Size: "+map.size());
    }
}

例1-2の出力は、次のとおりです。

Size: 2

Empty? false

Passing in keys and printing out values...

Key is apple, value is: fruit

Key is carrot, value is: vegetable

Inspecting keys and values:

Contains key "apple"? true

Contains key "carrot"? true

Contains key "fruit"? false

Contains key "vegetable"? false

Contains value "apple"? false

Contains value "carrot"? false

Contains value "fruit"? true

Contains value "vegetable"? true

Removing apple from the map...

Size: 1

Contains key "apple"? false

Invoking map.clear()...

Size: 0

このプログラムではまず、HashMap (Mapインタフェースの具象実装)がインスタンス化され、map変数に割り当てられます。キーと値のペアが、putメソッドを呼び出すことによってmapに追加されます。次に、size()およびisEmpty()を呼び出すことによって、マップに関する一定の情報が取得(および出力)されます。また、プログラムにより、所定のキーに対応する値を取得する方法が示されます(たとえば、map.get("apple")によって値fruitが返されます)。containsKeyおよびcontainsValueメソッドによって、特定のキーまたは値が存在するかどうかをテストする方法が示され、clearメソッドによってキーと値のマッピングがすべて削除されます。

Collections

ListおよびMapにあるメソッドに加えて、Collectionsクラスでは、コレクションを処理したりコレクションを返すいくつかのstaticユーティリティ・メソッドが公開されます。例1-3に、Listを作成し、Collectionsクラスを使用してその要素を逆転、スワップおよびソートすることにより、このようなメソッドのいくつかを示します。

例1-3 Collectionsクラスの使用

package collectionsdemo;
 
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
 
public class CollectionsDemo {
 
    public static void main(String[] args) {
        System.out.println("Creating the list...");
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        printElements(list);
        System.out.println("Reversing the elements...");
        Collections.reverse(list);
        printElements(list);
 
        System.out.println("Swapping the elements around...");
        Collections.swap(list, 0, 3);
        Collections.swap(list, 2, 0);
        printElements(list);
 
        System.out.println("Alphabetically sorting the elements...");
        Collections.sort(list);
        printElements(list);
    }
 
    private static void printElements(List<String> list) {
        for (Object o : list) {
            System.out.println(o.toString());
        }
    }
}

例1-3の出力は、次のとおりです。

Creating the list...

a

b

c

d

Reversing the elements...

d

c

b

a

Swapping the elements around...

b

c

a

d

Alphabetically sorting the elements...

a

b

c

d

このプログラムではまず、具象実装としてArrayListを使用して、Listに文字abcおよびdが追加されます。次に、Collections.reverse(list)を呼び出すことによって、リストの要素の順序を逆にします。List内で要素をスワップするために、Collections.swapメソッドが呼び出されます(たとえば、Collections.swap(list,0,3)によって、インデックス位置0および3の要素がスワップされます)。最後に、Collections.sort()メソッドによって、要素がアルファベット順にソートされます。

Java Collections Frameworkで最も関連性の高い領域を再確認し、CollectionsがJavaFXでどのように表されるかを学習する準備ができました。

JavaFX Collectionsの学習

JavaFXでのCollectionsはjavafx.collectionsパッケージにより定義されており、このパッケージは次のインタフェースおよびクラスで構成されています。

インタフェース

ObservableList: リスナーが変更をその発生時に追跡できるようにするリスト

ListChangeListener: ObservableListに対する変更の通知を受け取るインタフェース

ObservableMap: オブザーバが変更をその発生時に追跡できるようにするマップ

MapChangeListener: ObservableMapに対する変更の通知を受け取るインタフェース

クラス

FXCollections: java.util.Collectionsメソッドの1対1のコピーであるstaticメソッドで構成されるユーティリティ・クラス

ListChangeListener.Change: ObservableListに対して行われた変更を表す

MapChangeListener.Change: ObservableMapに対して行われた変更を表す

次の項では、これらのインタフェースおよびクラスを使用する方法について説明します。

ObservableList、ObservableMapおよびFXCollectionsの使用

javafx.collections.ObservableListjavafx.collections.ObservableMapの両方のインタフェースにより、javafx.beans.Observable (およびそれぞれjava.util.Listまたはjava.util.Map)が、監視可能性をサポートするListまたはMapを提供するように拡張されます。これらのインタフェースのいずれかのAPI仕様を確認すると、適切なリスナーを追加または削除するためのメソッドがわかります(ObservableListに対するListChangeListener、およびObservableMapに対するMapChangeListener)。前述のListおよびMapの例(具象実装としてArrayListおよびHashMapを使用)とは異なり、例1-4では、javafx.collections.FXCollectionsクラスを使用して、ObservableListおよびObservableMapオブジェクトを作成して返します。

例1-4 ObservableListの使用

package collectionsdemo;
 
import java.util.List;
import java.util.ArrayList;
import javafx.collections.ObservableList;
import javafx.collections.ListChangeListener;
import javafx.collections.FXCollections;
 
public class CollectionsDemo {
 
    public static void main(String[] args) {
 
        // Use Java Collections to create the List.
        List<String> list = new ArrayList<String>();
 
        // Now add observability by wrapping it with ObservableList.
    ObservableList<String> observableList = FXCollections.observableList(list);
        observableList.addListener(new ListChangeListener() {
 
            @Override
            public void onChanged(ListChangeListener.Change change) {
                System.out.println("Detected a change! ");
            }
        });
 
        // Changes to the observableList WILL be reported.
        // This line will print out "Detected a change!"
        observableList.add("item one");
 
        // Changes to the underlying list will NOT be reported
        // Nothing will be printed as a result of the next line.
        list.add("item two");
 
        System.out.println("Size: "+observableList.size());
 
    }
}

例1-4では、最初に標準のListが作成されます。次に、リストをFXCollections.observableList(list)に渡すことによって取得されたObservableListでラップされます。ListChangeListenerが登録されて、ObservableListに対して変更が行われるたびに通知を受け取るようになります。

ObservableMapに対する変更は、例1-5に示すように、同様の方法でリスンすることができます。

例1-5 ObservableMapの使用

package collectionsdemo;
 
import java.util.Map;
import java.util.HashMap;
import javafx.collections.ObservableMap;
import javafx.collections.MapChangeListener;
import javafx.collections.FXCollections;
 
public class CollectionsDemo {
 
    public static void main(String[] args) {
 
        // Use Java Collections to create the List.
        Map<String,String> map = new HashMap<String,String>();
 
        // Now add observability by wrapping it with ObservableList.
    ObservableMap<String,String> observableMap = FXCollections.observableMap(map);
        observableMap.addListener(new MapChangeListener() {
            @Override
            public void onChanged(MapChangeListener.Change change) {
                System.out.println("Detected a change! ");
            }
        });
 
        // Changes to the observableMap WILL be reported.
        observableMap.put("key 1","value 1");
        System.out.println("Size: "+observableMap.size());
        
        // Changes to the underlying map will NOT be reported.
        map.put("key 2","value 2");
        System.out.println("Size: "+observableMap.size());
 
    }
}

最後に、CollectionsまたはFXCollectionsからのstaticユーティリティ・メソッドを使用できます(リストの要素の順序を逆にするためなど)。ただし、FXCollectionsクラスでは、メソッドの呼出し時には少数の変更通知(通常は1つ)が生成されることに注意してください。他方で、Collectionsのメソッドを呼び出すと、例1-6に示すように、複数の変更通知が生成される可能性があります。

例1-6 CollectionsとFXCollectionsの変更通知

package collectionsdemo;
 
import java.util.List;
import java.util.ArrayList;
import javafx.collections.ObservableList;
import javafx.collections.ListChangeListener;
import javafx.collections.FXCollections;
 
public class CollectionsDemo {
 
    public static void main(String[] args) {
 
        // Use Java Collections to create the List
        List<String> list = new ArrayList<String>();
        list.add("d");
        list.add("b");
        list.add("a");
        list.add("c");
        
        // Now add observability by wrapping it with ObservableList
       ObservableList<String> observableList = FXCollections.observableList(list);
        observableList.addListener(new ListChangeListener() {
            @Override
            public void onChanged(ListChangeListener.Change change) {
                System.out.println("Detected a change! ");
            }
        });
        
        // Sort using FXCollections
        FXCollections.sort(observableList);
        
    }
}

例1-6では、行FXCollections.sort(obervableList)によってリスト内のStringオブジェクトがアルファベット順にソートされ、画面には変更通知が1つのみ出力されます。ただし、Collections.sort(observableList)を使用した場合は、変更通知が4回出力されます。

ListChangeListenerまたはMapChangeListenerを使用している場合、onChangedメソッドには、変更に関する情報をカプセル化するオブジェクトが必ず含まれます。これは、ListChangeListener.Change (ObservableListに対応)またはMapChangeListener.Change (ObservableMapに対応)のインスタンスです。ListChangeListener.Changeを使用する場合は、常に、変更オブジェクトへのすべてのコールを、change.next()を呼び出すループ内にラップしてください。例1-7に、この例を示します。

例1-7 ListChangeListener.Changeオブジェクトの問合せ

...
// This code will work with any of the previous ObservableList examples
observableList.addListener(new ListChangeListener() {
 
@Override
public void onChanged(ListChangeListener.Change change) {
    System.out.println("Detected a change! ");
    while (change.next()) {
        System.out.println("Was added? " + change.wasAdded());
        System.out.println("Was removed? " + change.wasRemoved());
        System.out.println("Was replaced? " + change.wasReplaced());
        System.out.println("Was permutated? " + change.wasPermutated());
        }
    }
});

...

例1-7では、ListChangeListener.Changeオブジェクトに対して様々なメソッドが呼び出されています。注意が必要な重要な点は、ListChangeListener.Changeオブジェクトに複数の変更が含まれる場合があるため、whileループでそのnext()メソッドをコールすることによって反復する必要があることです。ただし、MapChangeListener.Changeオブジェクトには、実行されたputまたはremove操作を表す変更のみが含まれます。

使用可能なメソッドの詳細は、ListChangeListener.ChangeおよびMapChangeListener.Change APIドキュメントを参照してください。

ウィンドウを閉じる

目次

JavaFX: JavaFX Collectionsの使用

展開 | 縮小