2015-08-31 11 views
6

den folgenden Code vor:Größe von Priorityqueue erhöht, wenn nicht vergleichbare Objekte hinzugefügt werden

import java.util.PriorityQueue; 

public class Test { 

    public static void main(String argv[]) { 
     PriorityQueue<A> queue = new PriorityQueue<>(); 
     System.out.println("Size of queue is " + queue.size()); // prints 0 
     queue.add(new A()); // does not throw an exception 
     try { 
      queue.add(new A()); // this time, an exception is thrown 
     } catch (ClassCastException ignored) { 
      System.out.println("An exception was thrown"); 
     } 
     System.out.println("Size of queue is " + queue.size()); // prints 2 
    } 

} 

class A { } // non-comparable object 

In diesem Code eine nicht vergleichbare Aufgabe wird zuerst zu einem PriorityQueue. Dieser Code funktioniert gut, as already answered here.

Dann wird ein zweites Objekt zu dieser Warteschlange hinzugefügt. Wie erwartet per PriorityQueue.add Javadoc wird eine ClassCastException geworfen, weil das zweite Objekt nicht mit dem ersten vergleichbar ist.

Allerdings scheint es, dass die Größe der Warteschlange erhöht wurde, obwohl eine Ausnahme ausgelöst wurde: die zweite print-Anweisung Ausgänge 2 statt 1

Ist dieses Verhalten erwartet? Wenn ja, was ist der Grund dafür und wo ist es dokumentiert?

Antwort

9

Laut GrepCode.com's version of the source, es sieht aus wie es könnte ein Fehler in ihrer Implementierung sein.

die alle Add-Funktion nicht ist

public boolean add(E e) { 
    return offer(e); 
} 

Die Funktion wie diese, die Größe Sie werden bemerken,

public boolean offer(E e) { 
    if (e == null) 
     throw new NullPointerException(); 
    modCount++; 
    int i = size; 
    if (i >= queue.length) 
     grow(i + 1); 
    size = i + 1; 
    if (i == 0) 
     queue[0] = e; 
    else 
     siftUp(i, e); 
    return true; 
} 

sieht Angebot rufen = i + 1 vor dem Punkt aufgerufen wird tatsächlich über eingeführt wird SiftUp. Wenn siftUp aufgerufen wird, versucht es als allererstes, nach Comparable zu wechseln und löst die Ausnahme aus, bevor das Element tatsächlich eingefügt wird. Daher wird die Größe erhöht, ohne dass tatsächlich ein Element eingefügt wird.

2

Der Quellcode für offer (bezeichnet durch add) offenbart den ungültigen Zustand, wenn die ein nicht Comparable Objekt zu einem PriorityQueue Passieren auftritt, das kein Comparator hat.

public boolean More offer(E e) { 
    if (e == null) 
     throw new NullPointerException(); 
    modCount++; 
    int i = size; 
    if (i >= queue.length) 
     grow(i + 1); 
    size = i + 1; 
    if (i == 0) 
     queue[0] = e; 
    else 
     siftUp(i, e); 
    return true; 
} 

Die Größe vor siftUp modifiziert wird aufgerufen. Die siftUp Methode, normalerweise verantwortlich für das Einfügen des Elements in die Warteschlange, (schließlich) wirft die ClassCastException, aber die Größe wurde bereits geändert, so dass die Größe nicht korrekt ist.

Es scheint nicht dokumentiert zu sein, dass der size inkrementiert wird, selbst wenn ein ClassCastException auftritt. Eine einfache Lösung wäre, die Zeile size = i + 1; nach dem if/else und vor der return-Anweisung zu platzieren.

Verwandte Themen