Links

  • 1. Sogeti
  • 2. JBoss
  • 3. IBM
  • 4. Oracle
  • 5. SpringSource
  • 6. NL-JUG
  • 7. Java

Archives

Syndication  RSS 2.0

RSS 1.0
RSS 2.0

Bookmark this site

Add 'JCN Blog' site to delicious  Add 'JCN Blog' site to technorati  Add 'JCN Blog' site to digg  Add 'JCN Blog' site to dzone

Posted by Stefan van der Steen at 11:45 on Friday 1 June    Add '‘Mijn object is immutable, want alles is final en ik heb geen Setters!’ – deel 2: Collections' site to delicious  Add '‘Mijn object is immutable, want alles is final en ik heb geen Setters!’ – deel 2: Collections' site to technorati  Add '‘Mijn object is immutable, want alles is final en ik heb geen Setters!’ – deel 2: Collections' site to digg  Add '‘Mijn object is immutable, want alles is final en ik heb geen Setters!’ – deel 2: Collections' site to dzone

In mijn vorige blog heb ik al uitgelegd wat een immutable object is en heb ik laten zien dat een Date bijvoorbeeld niet immutable is. Ook heb ik uitgelegd hoe je een Date object wel immutable kunt krijgen.

Nu is Date een leuk voorbeeld, maar de Java API bevat nog meer objecten die niet immutable zijn. Neem bijvoorbeeld een Collection als List of Set (of Map, maar dit is geen Collection). Ook deze zijn per definitie niet immutable, maar worden wel vaak gebruikt.

Voorbeeld


    public final class Boek
    {
        private final String titel;
        private final String auteur;
        private final String isbn;

        public Boek(String titel, String auteur, String isbn)
        {
            this.titel = titel;
            this.auteur = auteur;
            this.isbn = isbn;
        }

        public String getTitel()
        {
            return this.titel;
        }

        public String getAuteur()
        {
            return this.auteur;
        }

        public String getIsbn()
        {
            return this.isbn;
        }

        public String toString()
        {
            return "Het boek " + this.titel + " is geschreven door " +
                this.auteur + " (" + this.isbn + ")";
        }
    }


    public final class Boekenkast
    {
        private final Collection boeken;

        public Boekenkast()
        {
            boeken = new ArrayList();
        }

        public void addBoek(Boek boek)
        {
            this.boeken.add(boek);
        }

        public Collection getBoeken()
        {
            return this.boeken;
        }
    }

In dit voorbeeld heb ik ervoor gekozen om een boekenkast te bouwen. Deze boekenkast bevat een Collection met boeken. Een Boek heeft een titel, auteur en een ISBN nummer. Het is mogelijk om een Boek in de Collection toe te voegen en de gehele Collection met boeken op te vragen.

Neem nu de volgende test:


    public class BoekenkastTest
    {
        public static void main()
        {
            Boek cleanCode = new Boek("Clean Code", "Robert C. Martin", "0132350882");
            Boek refactoring = new Boek("Refactoring", "Martin Fowler", "0201485672");
            Boekenkast boekenkast = new Boekenkast();
            boekenkast.addBoek(cleanCode);
            boekenkast.addBoek(refactoring);

            System.out.println(boekenkast.getBoeken());
        }
    }

Zoals verwacht print deze test het volgende resultaat:

[Het boek Clean Code is geschreven door Robert C. Martin (0132350882), Het boek Refactoring is geschreven door Martin Fowler (0201485672)]

Maar wat nu als we de bovenstaande test uitbreiden met de volgende vier regels code:


    Boek designPatterns = new Boek("Design Patterns", "Erich Gamma", "0201633612");
    Collection boeken = boekenkast.getBoeken();
    boeken.add(designPatterns);
    System.out.println(boekenkast.getBoeken());

We vragen hier de volledige lijst op en voegen daar één boek aan toe. Je zou verwachten dat je het boek alleen toevoegt aan boeken, maar aangezien een Collection niet immutable is, is het resultaat van deze code als volgt:

[Het boek Clean Code is geschreven door Robert C. Martin (0132350882), Het boek Refactoring is geschreven door Martin Fowler (0201485672), Het boek Design Patterns is geschreven door Erich Gamma (0201633612)]

Een Collection is dus niet immutable!

Hoe maak je een Collection dan immutable?

Er zijn verschillende manieren te bedenken om een Collection immutable te maken. Allereerst is het mogelijk om een kopie te maken van de Collection en deze terug te geven:


    public Collection getBoeken()
    {
        return new ArrayList(this.boeken);
    }

Dit is dezelfde oplossing als in mijn vorige blog (defensive copy). Geef een kopie terug en de originele lijst kan alleen nog via addBoek gewijzigd worden. Deze manier is echter vrij lelijk en kost ook nog eens een hoop geheugen (de volledige lijst dient gekopieerd te worden en een lijst kan vrij groot zijn). Er is gelukkig een elegantere oplossing. De ontwikkelaars achter Java hebben hier namelijk ook al over nagedacht en hebben hier al iets op bedacht.

Binnen Java hebben we namelijk een Collections (let op de extra s) class. Nu bevat deze Collections class vele leuke en handige methodes (en ik adviseer dus ook deze eens goed door te kijken), maar in deze blog zal ik me concentreren op de volgende methodes:

  • unmodifiableCollection(Collection c)
  • unmodifiableList(List list)
  • unmodifiableMap(Map m)
  • unmodifiableSet(Set s)
  • unmodifiableSortedMap(SortedMap m)
  • unmodifiableSortedSet(SortedSet s)

Deze methodes geven een immutable view terug van de meegegeven Collection, List, Map of Set. We voegen dit als volgt toe in de code:


    public Collection getBoeken()
    {
        return Collections.unmodifiableCollection(this.boeken);
    }

Als ik nu de test uitvoer krijg ik het volgende resultaat te zien:


    java.lang.UnsupportedOperationException
        at java.util.Collections$UnmodifiableCollection.add(Collections.java:1075)
        at BoekenkastTest.main(BoekenkastTest.java:17)

De Collection is nu dus wel immutable!

Conclusie

Zoals ik in mijn vorige blog al aangaf is het niet zo dat een object immutable is wanneer alle velden final zijn en geen Setters zichtbaar zijn. Hier zal dus ten alle tijden rekening mee gehouden moeten worden.

Ook een Collection is dus niet immutable. Het is mogelijk om dit op te lossen middels defensive copy, maar dit is vrij lelijk, kost veel geheugen en er is een betere oplossing. Je kunt namelijk gebruik maken van de Collections class. Deze class zit in de standaard Java API.


© 2014 Java Competence Network. All Rights Reserved.