JAVA exPress > Archiwum > Numer 4 (2009-06-01) > Express killers, cz. III

Express killers, cz. III

W kolejnym odcinku zastanówmy się, jak maszyna wirtualna radzi sobie z drukowaniem referencji, która wskazuje na nic, czyli na null. Oto krótki kawałek kodu, który drukuje nazwę klasy obiektu pobranego z kolekcji:

 
            import java.util.ArrayList;
            import java.util.List;
 
            public class PrintNull {
 
                private static PrintNull o;
 
                public static void main(String[] args) {
                    List<PrintNull> list = new ArrayList<PrintNull>();
                    list.add(o);
                    for (PrintNull i : list) {
                        System.out.println(i.toString());
                    }
                }
 
                public String toString() {
                    return (this == null) ? "<null>" : super.toString();
                }
            }
 

Co zostanie wydrukowane na wyjście?

- null

- <null>

- za każdym razem inna wartość

- żadne z powyższych

Dziś bardzo krótki kawałek kodu i pytanie, co on robi – czy w ogóle coś robi, czy jest wynikiem poprawiania defektu poprzez usunięcie kawałka kodu, a nie całego bloku.

 
            synchronized(obj)
            {
            }
 

Odpowiedzi

Przykład pierwszy

Do kolekcji został dodany obiekt null, zatem taki też zostanie z niej pobrany w pętli. Próba wywołania metody na referencji, która nie wskazuje na żaden, obiekt skończy się rzuceniem wyjątku. Bezpieczniejsze byłoby tutaj użycie instrukcji:

 
            System.err.println(i);
 

co spowoduje wypisanie na wyjście "null" zamiast rzucenie wyjątku. Przesłonięcie metody toString() niczego w tym przypadku nie zmienia. Nie ma też znaczenia sprawdzenie, czy this nie jest null (wszakże kiedy jest to prawdą?).

Przykład drugi

Powyższy kawałek kodu odnalazłem niedawno w jednym ze źródeł i zastanawialiśmy się razem, czy ten blok jest zamierzony, czy jego zawartość została usunięta podczas kolejnych zmian w kodzie.

Na pierwszy rzut oka kod może wydawać się bez znaczenia, gdyż w bloku nie ma nic, co można by synchronizować. To prawda, ale jeśli przyjrzeć się szerszemu kontekstowi, to można dostrzec jego potrzebę, jeśli inne wątki zakładają mutex na referencji do obiektu tej klasy. Oto przykład kodu, który zachowuje się inaczej, jeśli blok w metodzie printTrue() zostanie usunięty, a inaczej, gdy będzie pozostawiony:

 
            public class Sync implements Runnable {
 
                private static final Object obj = new Object();
                private final boolean id;
 
                public Sync(boolean id) {
                    this.id = id;
                }
 
                public static void main(String[] args) {
                    new Thread(new Sync(false)).start();
                }
 
                public void run() {
                    System.err.println("start:" + id);
                    if (id) {
                        printTrue();
                    } else {
                        printFalse();
                    }
                    System.err.println("end:" + id);
                }
 
                public void printTrue() {
                    // zakomentuj te linijki i sprawdz, czy wynik będzie identyczny
                    synchronized (obj) {
                    }
                }
 
                public synchronized void printFalse() {
                    synchronized (obj) {
                        try {
                            new Thread(new Sync(true)).start();
                            wait(2000);
                            System.err.println("print");
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
 

Oczywiście wywołanie wait(2000) nie jest eleganckie i może zadziałać dla różnych implementacjach różnie (choć przy wartości 2 sekund efekt powinien być taki sam). Reasumując kod jest co najmniej dziwny i kwalifikuje się do wyrzucenia. Jednakże jego beztroskie usunięcie może mieć niepożądany skutek w działaniu programu.

Nie ma jeszcze komentarzy.

Tylko zalogowani użytkowincy mogą pisać komentarze

Developers World