Montag, 6. Juni 2011

 

Autoboxing in Java

Folgendes Beispiel zeigt ein Problem beim Autoboxing in Java. Der Autor des Code-Fragments will int-Werte in der LinkedList lockedRecords speichern. Das funktioniert beim Speichern in Zeile 16 auch super, weil der int-Wert recNo automatisch in ein Integer-Objekt gepackt wird.

LinkedList<Integer> lockedRecords = new LinkedList<Integer>();

    public long lock(int recNo) throws RemoteException,
            RecordNotFoundException {
        long lockCookie = 0;
        if(existsRec(recNo)){
            synchronized(records.get(recNo)){
                while(lockedRecords.contains(recNo)){
                    try {
                        records.get(recNo).wait();
                    } catch (InterruptedException ex) {
                        System.err.println("Lock Interrupted!");
                    }
                }
                if(existsRec(recNo)){
                    lockedRecords.add(recNo);
                    boolean lock_getted = true;
                    lockCookie = lockedRecords.size() -1;
                    return lockCookie;
                }
            }
        }else{
            throw new RecordNotFoundException();
        }
        return lockCookie;
    }

    public void unlock(int recNo, long lockCookie) throws RemoteException,
            RecordNotFoundException, SecurityException {
        if(recNo > 0 && recNo < records.size()){
            if(lockCookie >= 0 && lockCookie < lockedRecords.size()
                    && lockedRecords.contains((int)lockCookie)){
                synchronized(records.get(recNo)){
                    lockedRecords.remove(recNo);
                    records.get(recNo).notifyAll();
                }
            }else{
                throw new SecurityException();
            }
        }else{
            throw new RecordNotFoundException();
        }
    }
unlock() stürzt (praktisch) immer in Zeile 34 ab! Und zwar mit einer IndexOutOfBoundsException.

Warum?

Die Klasse LinkedList (sowie viele andere Klassen des Java Collection Frameworks) besitzt zwei remove()-Methoden:

  1. E remove(int index), welche das Element mit dem Index index entfernt und eine IndexOutOfBoundsException wirft, wenn der Index nicht existiert.
  2. boolean remove(Object o), welche das entsprechende Objekt entfernt, falls es existiert (und in diesem Fall true liefert).
Ein int-Parameter wird nicht automatisch in ein Integer-Objekt verpackt, da zuerst die zu int passende Methode verwendet wird! E remove(int index) wirft aber eine IndexOutOfBoundsException, wenn der int recNo kein gültiger Index ist. Das wäre eher zufällig passend.

Autoboxing ist also im Allgemeinen sehr praktisch, kann aber zu unerwarteten Problemen führen.

Übrigens ist eine Lösung mit Verwendung von Integer nicht zielführend, da beim Autoboxing nur bei kleinen Werten tatsächlich dasselbe Objekt verwendet wird:

Integer i1 = 23;
Integer i2 = 23;
Integer i3 = 2132321423;
Integer i4 = 2132321423;
System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
System.out.println(i3 == i4);
System.out.println(i3.equals(i4));
liefert:
true
true
false
true

Labels: ,


Kommentare:

Kommentar veröffentlichen

Abonnieren Kommentare zum Post [Atom]





<< Startseite

This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]