2016-07-29 16 views
12

Im Allgemeinen habe ich immer gesehen Try-with-Ressourcen verwendet, um eine neues Objekt Instanz deren close() Verfahren zuzuordnen ist aufgerufen, wie es out-of-scope geht.Verwendet Try-mit-Ressourcen ohne eine neue Objektinstanz schlechte Form?

Soweit ich feststellen kann, ist das Erstellen eines neuen Objekts keine Voraussetzung, und die Try-with-Resources-Syntax benötigt nur eine lokale Variable, um close() aufzurufen, wenn diese außerhalb des Bereichs liegt. Daher können Sie damit "gepaarte Operationen" steuern, wie z. B. das Zuweisen von Daten aus einem Pool und die Rückgabe.

Zum Beispiel myHandle unten zeigt, wie eine gepoolte Instanz freizugeben, wenn Sie nicht mehr benötigen:

// init 
class MyHandle implements AutoCloseable { 
    boolean inUse = false; 
    public MyHandle allocate() { 
     inUse = true; 
     return this; 
    } 

    public void close() { 
     inUse = false; 
    } 
} 

MyHandle[] pool = new MyHandle[POOL_SIZE]; 
for (int i = 0; i < pool.length; i++) { 
    pool[i] = new MyHandle(i); 
} 

// allocate 
MyHandle allocateFromPool() { 
    for (int i = 0; i < pool.length; i++) { 
     if (!pool[i].inUse) 
      return pool[i].allocate(); 
    } 
    throw new Exception("pool depleted"); 
} 

// using resources from the pool 

try (MyHandle handle = allocateFromPool()) { 
    // do something 
} 
// at this point, inUse==false for that handle... 

Sind die schlechte Form in Betracht gezogen?

EDIT: Ich denke, ich frage, ob es bessere Alternativen zum Aufbau dieser Art von Logik gibt, oder ob es einen großen Nachteil gibt, wenn man mit dem obigen Ansatz geht. Ich finde, dass die Verwendung dieses in einer Bibliothek für eine saubere API sorgt.

EDIT 2: Bitte ignorieren Sie Probleme im Codebeispiel, ich schrieb es inline in der SO Textfeld, um meine Frage mit einer Art von Beispiel zu verdeutlichen. Offensichtlich ist es kein echter Code! :)

+5

Es ist in Ordnung - das ist auch so, wenn man einen Verbindungspool benutzt: 'try (Verbindung c = pool_oder_datasource.getConnection()) {}' ... – assylias

Antwort

10

Die Try-with-Resource-Syntax ist als syntaktischer Sugaring gedacht, mit dem Sie sicherstellen können, dass Sie ein Objekt unabhängig von der Entsorgungslogik entsorgen. In Ihrem Fall wird das Objekt an den Pool zurückgegeben. Es ist absolut nichts Falsches daran, Try-with-Resource so zu verwenden. Es ist vielleicht nicht der gängigste Anwendungsfall dafür, aber es ist definitiv ein gültiger.

4

Unter den Abdeckungen werden die meisten Ressourcen (z. B. Dateideskriptoren) effektiv aus einem Pool vom Betriebssystem zugewiesen und dann beim Schließen an den Pool zurückgegeben.

Die Verwendung von Try-with-Ressourcen ist auf diese Weise absolut gültig.

N.B. Ihr Codebeispiel hat jedoch erhebliche Threading-Probleme, aber ich nehme an, dass die notwendige Threadsicherheit zur Klarheit in der Frage entfernt wurde. Ich erwähne es nur, weil Leute Ihren Code NICHT kopieren und in einer Implementierung verwenden sollten.

2

Nichts ist falsch mit Try-mit-Ressourcen wie das. Aber in Ihrem Fall würde ich befürchten, dass geschlossene Handles wiederverwendet werden, die von einem anderen Thread wieder geöffnet wurden.

Eine kleine Indirektion würde dieses Problem lösen, Rückgabe MyHandleWrapper anstelle des direkten Zugriffs auf MyHandle (allocateFromPool wird eine neue Instanz von MyHandleWrapper zurückgeben). Es wird nicht! lösen Sie alle anderen Threading-Probleme.

public class MyHandleWrapper extends MyHandle { 
    private MyHandle handle; 
    private boolean closed; 

    public void close() { 
     if(!closed){ 
      handle.inUse = false; 
     } 
     closed = true; 
    } 

    public void read() { 
     if (closed) { 
      throw new IllegalStateException("Already closed"); 
     } 
     handle.read(); 
    } 
} 

Grundsätzlich halten Sie die Informationen, wenn das Handle in MyHandleWrapper geschlossen wurde. Sie schützen jeden Zustand, der den Zugriff auf handle mit diesem Flag ändert, falls erforderlich, werfen Sie entsprechende Ausnahmen aus.