Monday, June 5, 2006

Collecties en mappen (Dutch)

Introductie

Naast de eenvoudige array operator [] kent Java een tal van klassen om collecties van diverse object referenties bij te houden. Ze vallen onder de interfaces Collection en Map. Er zijn een tal van klassen die deze interfaces implementeren, hierin worden alleen de belangrijkste en de handigste beschreven: ArrayList, Vector, TreeSet, HashSet, LinkedHashSet, TreeMap, HashMap, LinkedHashMap en Hashtable. Hieronder staat een overzichtje van de belangrijkste kenmerken en verschillen. De interfaces List en Set zijn subinterfaces van Collection.

collectie gebruikt
interface
synchroon
(thread safe)
heeft
sleutel
sorteerbaar
naar sleutel
accepteert
null sleutel
waarden in
volgorde
sorteerbaar
naar waarde
accepteert
null waarde
accepteert
duplicaten
ArrayList List nee index auto nvt ja ja ja ja
Vector List ja index auto nvt ja ja ja ja
TreeSet Set nee nee nvt nvt nee auto nee nee
HashSet Set nee nee nvt nvt nee nee ja nee
LinkedHashSet Set nee nee nvt nvt ja nee ja nee
TreeMap Map nee ja auto nee nee comparator ja ja
HashMap Map nee ja nee ja nee nee ja ja
LinkedHashMap Map nee ja nee ja ja nee ja ja
Hashtable Map ja ja nee nee nee nee nee ja

Let op: Hashtable schrijf je inderdaad met een kleine t!

Hier is een verklaring van de kenmerken:

synchroon (thread safe): de collectie kan maar éénmaal tegelijk worden aangeroepen, oftewel, het is singlethreaded en niet multithreaded. Dit geeft een grotere zekerheid aan de consistentie van de opgeslagen waarden. Het is wel een stuk langzamer ten opzichte van de asynchrone verwanten. Je kunt de asynchrone varianten desgewenst wel eenvoudig extern synchroon maken met behulp van Collections.synchronizedList(), Collections.synchronizedSet() en Collections.synchronizedMap().

heeft sleutel: met een sleutel kun je de bijbehorende waarde opvragen. Bij de gewone array's en bij de klassen van de interface List wordt de sleutel een index genoemd. Dat is een nummerieke sleutel met opeenvolgende nummers beginnend met 0 (nul). Wanneer je de derde waarde van de volgorde wil opvragen, dan moet je 2 (twee) gebruiken als index. Bij de klassen van de interface Map kan de sleutel een willekeurig object zijn. Vaak is dit voor het gemak gewoon een String.

sorteerbaar naar sleutel: indien "auto", dan geschiedt de sortering automatisch in de natuurlijke volgorde (1, 2, 3, A, a, B, b, C, c), ongeacht in welke volgorde je de waarden toevoegt. Bij de TreeMap kun je ook kun je zelf een Comparator schrijven om de automatische sortering te beïnvloeden. Indien "nee", dan is het niet zonder meer sorteerbaar. Er is geen "ja".

accepteert null sleutel: hiermee wordt bedoeld of het mogelijk is om een lege referentie-variabele aan de sleutel te toewijzen. Een lege referentie-variabele heeft de waarde null. Bij de klassen van de interface List is de sleutel van het datatype int en deze kan niet null zijn.

waarden in volgorde: hiermee wordt bedoeld of de waarden in de volgorde zitten zoals je ze toevoegt. Dus elk nieuw toegevoegde waarde wordt telkens achteraan de collectie gezet. Bij de TreeSet en TreeMap worden de waarden na elke toevoeging automatisch gesorteerd. Bij de HashSet, HashMap en Hashtable zitten de waarden niet in een vaste volgorde.

sorteerbaar naar waarde: indien "ja", dan is het sorteerbaar met behulp van Collections.sort(). Indien "auto", dan geschiedt de sortering automatisch in de natuurlijke volgorde (1, 2, 3, A, a, B, b, C, c), ongeacht in welke volgorde je de waarden toevoegt, ook kun je zelf een Comparator schrijven om de automatische sortering te beïnvloeden. Indien "comparator", dan zul je eerst zelf een Comparator moeten schrijven om de automatische sortering te beïnvloeden. Indien "nee", dan is het niet zonder meer sorteerbaar.

accepteert null waarde: hiermee wordt bedoeld of het mogelijk is om een lege referentie-variabele aan de waarde te toewijzen. Een lege referentie-variabele heeft de waarde null.

accepteert duplicaten: hiermee wordt bedoeld of het mogelijk is om meerdere identieke waarden in de collectie te opslaan. Let wel, alleen dubbele waarden en geen dubbele sleutels, de sleutels moeten altijd uniek zijn.

Terug naar boven

Welke moet ik gebruiken?

De belangrijkste beweegredenen zijn:

List: wanneer je een groep waarden met een index wilt hebben. Bijvoorbeeld de hoeveelheid aangemaakte auto's per maand, gesorteerd naar de maandnummer.

Set: wanneer je een groep unieke waarden zonder een index of sleutel wilt hebben. Bijvoorbeeld een lijstje met alle toegestane automerknamen.

Map: wanneer je een groep waarden met een object als sleutel wilt hebben. Bijvoorbeeld een overzicht van alle aangemaakte auto's, gegroepeerd naar de klasse van de automerk.

Voor de rest zijn het de kleine dingetjes die het van belang zijn bij de keuze: synchroniteit, sorteerbaarheid, het vasthouden van de volgorde en de acceptatie van null danwel duplicaten. Zie dus ook de tabel hierboven.

Terug naar boven

Waarden toevoegen

Bij de Collection kan dit met behulp van de add() methode en bij de Map met behulp van de put() methode.

public class TestCollecties {

    // Even declareren en initialiseren.
    // Declareer bij voorkeur naar de interface.
    List arrayList = new ArrayList();
    List vector = new Vector();
    Set treeSet = new TreeSet();
    Set hashSet = new HashSet();
    Set linkedHashSet = new LinkedHashSet();
    Map treeMap = new TreeMap();
    Map hashMap = new HashMap();
    Map linkedHashMap = new LinkedHashMap();
    Map hashtable = new Hashtable();

    public void waardenToevoegen() {

        // Waarden toevoegen zonder sleutel.
        arrayList.add("ArrayList waarde 1");
        vector.add("Vector waarde 1");
        treeSet.add("TreeSet waarde 1");
        hashSet.add("HashSet waarde 1");
        linkedHashSet.add("LinkedHashSet waarde 1");
        // TreeMap: niet mogelijk.
        // HashMap: niet mogelijk.
        // LinkedHashMap: niet mogelijk.
        // Hashtable: niet mogelijk.

        // Waarden toevoegen met sleutel.
        // ArrayList: niet mogelijk.
        // Vector: niet mogelijk.
        // TreeSet: niet mogelijk.
        // HashSet: niet mogelijk.
        // LinkedHashSet: niet mogelijk.
        treeMap.put("TreeMap sleutel 1", "TreeMap waarde 1");
        hashMap.put("HashMap sleutel 1", "HashMap waarde 1");
        linkedHashMap.put("LinkedHashMap sleutel 1", "LinkedHashMap waarde 1");
        hashtable.put("Hashtable sleutel 1", "Hashtable waarde 1");
    }

}

Bij de klassen van de interface List wordt de index automatisch toegewezen wanneer je een waarde zonder de sleutel (index) toewijst. De index wordt stapsgewijs verhoogd vanaf de 0 (nul) en is afhankelijk van de huidige grootte.

Terug naar boven

Waarden opvragen

Dit kan met behulp van de get() methode.

public class TestCollecties {

    public void waardenOpvragen() {

        // Waarden opvragen via sleutel.
        Object o1 = arrayList.get(1);
        Object o2 = vector.get(1);
        // TreeSet: niet mogelijk.
        // HashSet: niet mogelijk.
        // LinkedHashSet: niet mogelijk.
        Object o3 = treeMap.get("TreeMap sleutel 1");
        Object o4 = hashMap.get("HashMap sleutel 1");
        Object o5 = linkedHashMap.get("LinkedHashMap sleutel 1");
        Object o6 = hashtable.get("Hashtable sleutel 1");
    }

}
Terug naar boven

Aanwezigheid controleren

Je kunt met behulp van de contains() methode controleren of een bepaalde waarde in de collectie voorkomt. Dit geeft een booleanse antwoord.

public class TestCollecties {

    public void aanwezigheidControleren() {

        // Aanwezigheid van de waarde controleren.
        boolean b1 = arrayList.contains("ArrayList waarde 1");
        boolean b2 = vector.contains("Vector waarde 1");
        boolean b3 = treeSet.contains("TreeSet waarde 1");
        boolean b4 = hashSet.contains("HashSet waarde 1");
        boolean b5 = linkedHashSet.contains("LinkedHashSet waarde 1");
        boolean b6 = treeMap.containsValue("TreeMap waarde 1");
        boolean b7 = hashMap.containsValue("HashMap waarde 1");
        boolean b8 = linkedHashMap.containsValue("LinkedHashMap waarde 1");
        boolean b9 = hashtable.containsValue("Hashtable waarde 1");

        // Bij de mappen kun je ook de aanwezigheid van de sleutel controleren.
        boolean b10 = treeMap.containsKey("TreeMap sleutel 1");
        boolean b11 = hashMap.containsKey("HashMap sleutel 1");
        boolean b12 = linkedHashMap.containsKey("LinkedHashMap sleutel 1");
        boolean b13 = hashtable.containsKey("Hashtable sleutel 1");
    }

}
Terug naar boven

Waarden wijzigen

Hierbij gebruik je dezelfde methoden als bij het toevoegen van de waarden, maar dan geef je ook de sleutel mee om te aangeven welke waarde gewijzigd (in feite: overgeschreven) moet worden. Bij de Collection kan dit dus met behulp van de add() methode en bij de Map met behulp van de put() methode.

public class TestCollecties {

    public void waardenWijzigen() {

        // Waarden wijzigen (overschrijven) via sleutel.
        // Dit is eenvoudig, gebruik gewoon de identieke sleutel.
        arrayList.add(1, "ArrayList nieuwe waarde 1");
        vector.add(1, "Vector nieuwe waarde 1");
        // TreeSet: niet mogelijk.
        // HashSet: niet mogelijk.
        // LinkedHashSet: niet mogelijk.
        treeMap.put("TreeMap sleutel 1", "TreeMap nieuwe waarde 1");
        hashMap.put("HashMap sleutel 1", "HashMap nieuwe waarde 1");
        linkedHashMap.put("LinkedHashMap sleutel 1", "LinkedHashMap nieuwe waarde 1");
        hashtable.put("Hashtable sleutel 1", "Hashtable nieuwe waarde 1");
    }

}
Terug naar boven

Waarden verwijderen

Dit kan met behulp van de remove() methode, waarbij je de sleutel opgeeft. Dit retourneert het zojuist verwijderde object.

public class TestCollecties {

    public void waardenVerwijderen() {

        // Waarden verwijderen zonder sleutel.
        Object o1a = arrayList.remove("ArrayList waarde 1");
        Object o2a = vector.remove("Vector waarde 1");
        Object o3 = treeSet.remove("TreeSet waarde 1");
        Object o4 = hashSet.remove("HashSet waarde 1");
        Object o5 = linkedHashSet.remove("LinkedHashSet waarde 1");
        // TreeMap: niet mogelijk.
        // HashMap: niet mogelijk.
        // LinkedHashMap: niet mogelijk.
        // Hashtable: niet mogelijk.

        // Waarden verwijderen via sleutel.
        Object o1b = arrayList.remove(0);
        Object o2b = vector.remove(0);
        // TreeSet: niet mogelijk.
        // HashSet: niet mogelijk.
        // LinkedHashSet: niet mogelijk.
        Object o6 = treeMap.remove("TreeMap sleutel 1");
        Object o7 = hashMap.remove("HashMap sleutel 1");
        Object o8 = linkedHashMap.remove("LinkedHashMap sleutel 1");
        Object o9 = hashtable.remove("Hashtable sleutel 1");
    }

}
Terug naar boven

Grootte opvragen

Je kunt ook de hoeveelheid opgeslagen waarden van een collectie opvragen. Dit kan met behulp van de size() methode. Dit retourneert een int.

public class TestCollecties {

    public void grootteOpvragen() {

        // De grootte opvragen (de huidige aantal waarden).
        int arrayListGrootte = arrayList.size();
        int vectorGrootte = vector.size();
        int treeSetGrootte = treeSet.size();
        int hashSetGrootte = hashSet.size();
        int linkedHashSetGrootte = linkedHashSet.size();
        int treeMapGrootte = treeMap.size();
        int hashMapGrootte = hashMap.size();
        int linkedHashMapGrootte = linkedHashMap.size();
        int hashtableGrootte = hashtable.size();
    }

}
Terug naar boven

Leeg maken

Dit kan met behulp van de clear() methode.

public class TestCollecties {

    public void leegMaken() {

        // Leeg maken.
        arrayList.clear();
        vector.clear();
        treeSet.clear();
        hashSet.clear();
        linkedHashSet.clear();
        treeMap.clear();
        hashMap.clear();
        linkedHashMap.clear();
        hashtable.clear();
    }

}
Terug naar boven

Collectie doorlopen

Dit kun je doen met de handige interface Iterator. Alle klassen van de interface Collection ondersteunen deze interface. Het werkt vrij eenvoudig, hier is een voorbeeldje met de ArrayList.

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList = new ArrayList();

        // Voeg de waarden toe.
        arrayList.add("ArrayList waarde 1");
        arrayList.add("ArrayList waarde 2");
        arrayList.add("ArrayList waarde 3");

        // Declareer en initialiseer de Iterator.
        Iterator arrayListIterator = arrayList.iterator();
        
        // Doorloop de waarden.
        while (arrayListIterator.hasNext()) {
            String value = (String) arrayListIterator.next();
            System.out.println(value);
        }
    }

}

ArrayList waarde 1
ArrayList waarde 2
ArrayList waarde 3

Bij de klassen van de interface List kun je trouwens ook met een herhaal-statement de collectie doorlopen. Al is het gebruik van de Iterator veel netter.

        // Declareer en initialiseer een ArrayList.
        List arrayList = new ArrayList();

        // Voeg de waarden toe.
        arrayList.add("ArrayList waarde 1");
        arrayList.add("ArrayList waarde 2");
        arrayList.add("ArrayList waarde 3");

        // Doorloop de waarden met behulp van een while loop.
        int i = 0;
        while (i < arrayList.size()) {
            System.out.println(arrayList.get(i++));
        }

        // Of met behulp van een for loop.
        for (int j = 0; j < arrayList.size(); j++) {
            System.out.println(arrayList.get(j));
        }

        // Of met behulp van een do-while loop.
        int k = 0;
        do {
            System.out.println(arrayList.get(k));
        } while (++k < arrayList.size());

Je kunt de Iterator overigens ook in een for loop gebruiken.

        // Gebruik de Iterator in een for loop.
        for (Iterator iter = arrayList.iterator(); iter.hasNext();) {
            System.out.println(iter.next());
        }

Vanaf Java 5.0 kun je de for loop voor arrays ook bij collecties gebruiken, zie ook Generics.

        // Gebruik de for loop voor arrays.
        for (Object object : arrayList) {
            System.out.println(object);
        }

Maar dan mis je wel de in sommige gevallen handige hasNext() (om het laatste object te detecteren) en de remove() (om een object gelijk in een loop te verwijderen) methoden van de Iterator.

Terug naar boven

Map doorlopen

Bij alle klassen van de interface Map zou je eerst alle waarden via de values() methode van de Map moeten converteren naar een willekeurige Collection, voordat je met de Iterator door de waarden heen kunt lopen. Daarnaast kun je de sleutels via de keySet() methode van de Map opvangen in een Set en wederom met de Iterator doorheen lopen. Hieronder staat een voorbeeldje met de HashMap.

package test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een HashMap.
        Map hashMap = new HashMap();

        // Voeg de waarden toe.
        hashMap.put("HashMap sleutel 1", "HashMap waarde 1");
        hashMap.put("HashMap sleutel 2", "HashMap waarde 2");
        hashMap.put("HashMap sleutel 3", "HashMap waarde 3");

        // Zet de waarden in een Collection object.
        Collection hashMapValues = hashMap.values();
        
        // Of als je het per-se in een List of Set wilt zetten:
        // List hashMapValues = new ArrayList(hashMap.values());
        // Set hashMapValues = new TreeSet(hashMap.values());
        
        // Declareer en initialiseer de Iterator.
        Iterator hashMapValuesIterator = hashMapValues.iterator();
        
        // Doorloop de waarden.
        while (hashMapValuesIterator.hasNext()) {
            String value = (String) hashMapValuesIterator.next();
            System.out.println(value);
        }

        // Zet de sleutels in een Set object.
        Set hashMapKeySet = hashMap.keySet();
        
        // Declareer en initialiseer de Iterator.
        Iterator hashMapKeySetIterator = hashMapKeySet.iterator();
        
        // Doorloop de sleutels.
        while (hashMapKeySetIterator.hasNext()) {
            String key = (String) hashMapKeySetIterator.next();
            System.out.println(key);
        }
        
        // Herinitialiseer de Iterator.
        hashMapKeySetIterator = hashMapKeySet.iterator();
        
        // Doorloop zowel de sleutels als de waarden.
        while (hashMapKeySetIterator.hasNext()) {
            String key = (String) hashMapKeySetIterator.next();
            System.out.println(key + ", " + hashMap.get(key));
        }
    }

}

HashMap waarde 1
HashMap waarde 2
HashMap waarde 3
HashMap sleutel 1
HashMap sleutel 2
HashMap sleutel 3
HashMap sleutel 1, HashMap waarde 1
HashMap sleutel 2, HashMap waarde 2
HashMap sleutel 3, HashMap waarde 3

Let op: de volgorde kan verschillen, aangezien de HashMap geen vaste volgorde aanhoudt. Mocht je dat wel willen hebben, gebruik dan LinkedHashMap.

Vanaf Java 5.0 kun je de for loop voor arrays ook bij collecties gebruiken, zie ook Generics. Dit geldt dus ook voor de keySet():

        // Gebruik de for loop voor arrays.
        for (Object key : hashMap.keySet()) {
            System.out.println(key + ", " + hashMap.get((String) key));
        }

Maar dan mis je wel de in sommige gevallen handige hasNext() (om het laatste object te detecteren) en de remove() (om een object gelijk in een loop te verwijderen) methoden van de Iterator.

Terug naar boven

Collectie sorteren

Bij de klassen van de interface List kun je de waarden sorteren met Collections.sort(). Verder kun je de huidige volgorde omkeren met Collections.reverse().

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList = new ArrayList();

        // Voeg de waarden toe.
        arrayList.add("ArrayList waarde 3");
        arrayList.add("ArrayList waarde 1");
        arrayList.add("ArrayList waarde 2");

        // Toon ongesorteerde ArrayList.
        System.out.println("Ongesorteerde ArrayList.");
        for (Object object : arrayList) {
            System.out.println(object);
        }

        // Keer de volgorde om.
        Collections.reverse(arrayList);

        // Toon de omgekeerde ArrayList.
        System.out.println("Omgekeerde ArrayList.");
        for (Object object : arrayList) {
            System.out.println(object);
        }

        // Sorteer ArrayList oplopend.
        Collections.sort(arrayList);

        // Toon oplopend gesorteerde ArrayList.
        System.out.println("Oplopend gesorteerde ArrayList.");
        for (Object object : arrayList) {
            System.out.println(object);
        }

        // Sorteer ArrayList aflopend.
        Collections.sort(arrayList, Collections.reverseOrder());

        // Toon aflopend gesorteerde ArrayList.
        System.out.println("Aflopend gesorteerde ArrayList.");
        for (Object object : arrayList) {
            System.out.println(object);
        }
    }

}

Ongesorteerde ArrayList.
ArrayList waarde 3
ArrayList waarde 1
ArrayList waarde 2
Omgekeerde ArrayList.
ArrayList waarde 2
ArrayList waarde 1
ArrayList waarde 3
Oplopend gesorteerde ArrayList.
ArrayList waarde 1
ArrayList waarde 2
ArrayList waarde 3
Aflopend gesorteerde ArrayList.
ArrayList waarde 3
ArrayList waarde 2
ArrayList waarde 1

Terug naar boven

Collecties samenvoegen en splitsen

Hiervoor zijn de volgende methoden beschikbaar: addAll(), removeAll() en retainAll, waarbij je de tweede collectie als parameter opgeeft. Alle waarden komen dan in de aanroepende collectie terecht. De tweede collectie die als parameter is opgegeven blijft ongewijzigd.

De methode addAll() voegt twee collecties samen. Bij de collecties die duplicaten toestaan, zoals List, worden de duplicaten gewoon toegestaan. Bij de collecties die geen duplicaten toestaan, zoals Set, worden de duplicaten gewoon weggefilterd.

Een voorbeeld met de ArrayList:

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList1 = new ArrayList();

        // Voeg de waarden toe.
        arrayList1.add("ArrayList waarde 1");
        arrayList1.add("ArrayList waarde 2");
        arrayList1.add("ArrayList waarde 3");

        // Declareer en initialiseer de tweede ArrayList.
        List arrayList2 = new ArrayList();

        // Voeg de waarden toe.
        arrayList2.add("ArrayList waarde 3");
        arrayList2.add("ArrayList waarde 4");
        arrayList2.add("ArrayList waarde 5");

        // Voeg de collecties samen in arrayList1.
        arrayList1.addAll(arrayList2);

        // Doorloop de waarden.
        for (Object object : arrayList1) {
            System.out.println(object);
        }
    }

}

ArrayList waarde 1
ArrayList waarde 2
ArrayList waarde 3
ArrayList waarde 3
ArrayList waarde 4
ArrayList waarde 5

De methode removeAll() verwijdert de overeenkomende waarden van de aanroepende collectie:

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList1 = new ArrayList();

        // Voeg de waarden toe.
        arrayList1.add("ArrayList waarde 1");
        arrayList1.add("ArrayList waarde 2");
        arrayList1.add("ArrayList waarde 3");

        // Declareer en initialiseer de tweede ArrayList.
        List arrayList2 = new ArrayList();

        // Voeg de waarden toe.
        arrayList2.add("ArrayList waarde 3");
        arrayList2.add("ArrayList waarde 4");
        arrayList2.add("ArrayList waarde 5");

        // Verwijder de overeenkomende waarden uit arrayList1.
        arrayList1.removeAll(arrayList2);

        // Doorloop de waarden.
        for (Object object : arrayList1) {
            System.out.println(object);
        }
    }

}

ArrayList waarde 1
ArrayList waarde 2

De methode retainAll() haalt de overeenkomende waarden uit de collecties en zet deze in de aanroepende collectie (of beter: verwijdert de niet-overeenkomende waarden). Voorbeeldje:

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList1 = new ArrayList();

        // Voeg de waarden toe.
        arrayList1.add("ArrayList waarde 1");
        arrayList1.add("ArrayList waarde 2");
        arrayList1.add("ArrayList waarde 3");

        // Declareer en initialiseer de tweede ArrayList.
        List arrayList2 = new ArrayList();

        // Voeg de waarden toe.
        arrayList2.add("ArrayList waarde 3");
        arrayList2.add("ArrayList waarde 4");
        arrayList2.add("ArrayList waarde 5");

        // Verwijder de niet-overeenkomende waarden uit arrayList1.
        arrayList1.retainAll(arrayList2);

        // Doorloop de waarden.
        for (Object object : arrayList1) {
            System.out.println(object);
        }
    }

}

ArrayList waarde 3

Terug naar boven

Duplicaten verwijderen uit een List

Dit is simpel: converteer de List even naar een Set en daarna weer terug naar een List. Een Set accepteert uit zich namelijk al geen duplicaten. Ze worden dus "automatisch" verwijderd.

Hieronder staat een voorbeeld van de conversie van een ArrayList naar een LinkedHashSet en terug. Er is voor de LinkedHashSet gekozen, omdat de ArrayList null waarden kan bevatten en dat alle waarden in een vaste volgorde staan. Hierdoor vallen de TreeSet respectievelijk HashSet af.

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList = new ArrayList();

        // Voeg de waarden toe.
        arrayList.add("ArrayList waarde 1");
        arrayList.add("ArrayList waarde 2");
        arrayList.add("ArrayList waarde 1");
        arrayList.add("ArrayList waarde 3");
        arrayList.add("ArrayList waarde 2");
        arrayList.add("ArrayList waarde 3");

        // Converteer de List even naar een Set en dan weer terug.
        arrayList = new ArrayList(new LinkedHashSet(arrayList));

        // Doorloop de waarden.
        for (Object object : arrayList) {
            System.out.println(object);
        }
    }

}

ArrayList waarde 1
ArrayList waarde 2
ArrayList waarde 3

Terug naar boven

Converteren tussen Collection en Map

Hiervoor zijn geen directe methoden beschikbaar. Je kunt een Map niet direct in z'n geheel converteren naar een Collection, simpelweg omdat de sleutels van de mappen objecten zijn en die van de collecties van het datatype int zijn. Je kunt echter wel alle sleutels en waarden apart converteren. Je kunt met de keySet() methode van de Map alle sleutels opvangen in een Set en met de values() methode kun je alle waarden in een Collection zetten. Hoe je dit kunt doen staat reeds hierboven bij Map doorlopen uitgelegd.

En omgekeerd kun je het beste met behulp van een herhaal-statement de index en de waarden van een Collection in een Map zetten. Ervan uitgaande dat je de index van de Collection wilt gebruiken als de sleutel van de Map, moeten we de int waarde van de index in een de wrapper object Integer zetten. De Map accepteert namelijk alleen maar objecten als sleutels.

Hier volgt een voorbeeldje van een conversie van ArrayList naar LinkedHashMap met behulp van de for statement.

package test;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList = new ArrayList();

        // Voeg de waarden toe.
        arrayList.add("ArrayList waarde 1");
        arrayList.add("ArrayList waarde 2");
        arrayList.add("ArrayList waarde 3");

        // Declareer en initialiseer een LinkedHashMap.
        Map linkedHashMap = new LinkedHashMap();

        // Doorloop de ArrayList en zet de waarden in een LinkedHashMap.
        for (int i = 0; i < arrayList.size(); i++) {
            linkedHashMap.put(new Integer(i), arrayList.get(i));
        }

        // Bekijk de inhoud van de LinkedHashMap.
        System.out.println(linkedHashMap.toString());
    }

}

{0=ArrayList waarde 1, 1=ArrayList waarde 2, 2=ArrayList waarde 3}

Terug naar boven

Converteren tussen Collection en Array

Je kunt met de toArray() methode van de Collection interface een collectie converteren naar een ordinaire object-array Object[]. Verder kun je met Arrays.asList() een ordinaire object-array Object[] converteren naar de interface List.

Hieronder staat een voorbeeldje van een conversie van ArrayList naar Object[].

package test;

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList = new ArrayList();

        // Voeg de waarden toe.
        arrayList.add("ArrayList waarde 1");
        arrayList.add("ArrayList waarde 2");
        arrayList.add("ArrayList waarde 3");

        // Converteer van ArrayList naar Object[].
        Object[] array = arrayList.toArray();
        
        // Of als je het per-se in een String[] wil hebben:
        // String[] array = arrayList.toArray(new String[arrayList.size()]);
        
        // Doorloop de waarden.
        for (Object object : array) {
            System.out.println(object);
        }
    }

}

ArrayList waarde 1
ArrayList waarde 2
ArrayList waarde 3

En dan nu de conversie van String[] naar List.

package test;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ordinaire String array.
        String[] array = new String[3];

        // Voeg de waarden toe.
        array[0] = "Array waarde 1";
        array[1] = "Array waarde 2";
        array[2] = "Array waarde 3";

        // Converteer van String[] naar List.
        List list = Arrays.asList(array);
        
        // Of als je het per-se in een ArrayList wil hebben:
        // List list = new ArrayList(Arrays.asList(array));
        
        // Doorloop de waarden.
        for (Object object : list) {
            System.out.println(object);
        }
    }

}

Array waarde 1
Array waarde 2
Array waarde 3

En tenslotte de conversie van String[] naar Set. Dit is eenvoudig, zet de geconverteerde List in de constructeur van een Set implementatie, zoals de LinkedHashSet.

package test;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ordinaire String array.
        String[] array = new String[3];

        // Voeg de waarden toe.
        array[0] = "Array waarde 1";
        array[1] = "Array waarde 2";
        array[2] = "Array waarde 3";

        // Converteer van String[] naar Set.
        Set set = new LinkedHashSet(Arrays.asList(array));
        
        // Doorloop de waarden.
        for (Object object : set) {
            System.out.println(object);
        }
    }

}

Array waarde 1
Array waarde 2
Array waarde 3

Terug naar boven

Converteren tussen Map en Array

Dit is niet zonder meer te doen, je kunt het beste eerst de Map converteren naar Collection en vervolgens de Collection converteren naar een ordinaire object-array Object[].

Dit staat gespreid uitgelegd in Converteren tussen Collection en Map en Converteren tussen Collection en Array.

Terug naar boven

Reflecties

Aangezien deze collecties en mappen louter object referenties (en dus niet de objecten zélf) bijhouden worden alle veranderingen in de objecten direct in de collectie gereflecteerd. Mocht je eerder hebben geprogrammeerd in een procedurele (niet object-oriented) taal, dan zal dit in beginsel wel erg wennen zijn. Als je het eenmaal doorhebt, dan zul je het alleen maar handig vinden. Zo hoef je niet bijvoorbeeld in een loop het hele object uit de collectie te halen, deze te aanpassen en dan terug te stoppen, je hebt immers genoeg aan de object referentie.

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        // Declareer en initialiseer een ArrayList.
        List arrayList = new ArrayList();

        // Voeg de waarden toe.
        arrayList.add("ArrayList waarde 1");
        arrayList.add("ArrayList waarde 2");
        arrayList.add("ArrayList waarde 3");

        // Zet de ArrayList in een andere collectie. In feite wordt alleen
        // de referentie "arrayList" toegevoegd en niet het object zelf.
        Map hashMap = new HashMap();
        hashMap.put("myList", arrayList);
        
        // Laat de inhoud van de hashMap zien.
        System.out.println(hashMap);
        
        // Voeg een nieuwe waarde toe aan de "arrayList" referentie.
        arrayList.add("ArrayList waarde 4");
        
        // Laat de inhoud van de hashMap opnieuw zien.
        System.out.println(hashMap);
        
        // Dus je hoeft niet zo te werken zoals bij procedurele talen.
        List myList = (List) hashMap.get("myList");
        myList.add("ArrayList waarde 4");
        hashMap.put("myList", myList);
    }

}

{myList=[ArrayList waarde 1, ArrayList waarde 2, ArrayList waarde 3]}
{myList=[ArrayList waarde 1, ArrayList waarde 2, ArrayList waarde 3, ArrayList waarde 4]}

Terug naar boven

Generics

In een goede IDE zou je vanaf Java 5.0 de volgende waarschuwingen kunnen krijgen.

Voor een willekeurige List:

List is a raw type. References to generic type List<E> should be parameterized.
ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized.
Type safety: The method add(Object) belongs to the raw type List. References to generic type List<E> should be parameterized.

En voor een willekeurige Set:

Set is a raw type. References to generic type Set<E> should be parameterized.
HashSet is a raw type. References to generic type HashSet<E> should be parameterized.
Type safety: The method add(Object) belongs to the raw type Set. References to generic type Set<E> should be parameterized.

En tenslotte voor een willekeurige Map:

Map is a raw type. References to generic type Map<K, V> should be parameterized.
HashMap is a raw type. References to generic type HashMap<K, V> should be parameterized.
Type safety: The method put(Object, Object) belongs to the raw type Map. References to generic type Map<K, V> should be parameterized.

Dit betekent allemaal in feite niks anders dan dat de gedeclareerde collecties en mappen ongeneriek zijn. Hoe dit te verhelpen staat in het volgende hoofdstuk: Generics.

Terug naar boven

Copyright - Er is geen copyright op de code. Je kunt het naar believen overnemen, aanpassen danwel verspreiden.

(C) Juni 2006, BalusC

No comments: