2010-05-31 6 views
6

Gibt es so etwas wie Python mit Kontext-Manager in Java?Simulieren Python mit With-Anweisung in Java

Zum Beispiel sagt, dass ich so etwas wie die folgende tun:

getItem(itemID){ 
    Connection c = C.getConnection(); 
    c.open(); 
    try{ 
    Item i = c.query(itemID); 
    }catch(ALLBunchOfErrors){ 
     c.close(); 
    } 

    c.close(); 
    return c; 
} 

wo in Python ich nur noch:

with(C.getConnection().open() as c): 
    Item i = c.query(itemID); 
    return i; 
+2

Ich weiß nicht viel über 'mit' oder Python für die Angelegenheit, aber wenn es so etwas wie C# '' using' ist, wurde dies kürzlich beantwortet: http://stackoverflow.com/questions/ 2943542/using-keyword-in-java –

+0

+1 aber: '[const]' '[final]' existiert auch, also sollte '[with]' auch ein Tag haben. Ich kann es noch nicht schaffen. – n611x007

Antwort

5

Im Moment nicht; Java hat für dieses Muster noch keinen syntaktischen Zucker hinzugefügt. Dennoch wird es nicht so sauber wie with (Python) oder using (C#), aber Sie können das zumindest ein wenig aufräumen, indem Sie einfach einen Anruf an c.close() innerhalb eines finally Blocks statt zweimal wie Sie haben getan:

try { 
    // use c 
} finally { 
    c.close() 
} 

Dies bringt es auch im Einklang mit, wie sowohl with und using tatsächlich umgesetzt werden, was ein try..finally Block (kein try..catch).

+0

Danke ... Ich Gast könnte ich auch eine Vorlage Methode Muster, die hässliche Klassenhierarchie erfordert. Prost. – drozzy

3

Wie Tzaman sagte, nutzt das Geheimnis schließlich; allgemein:

Resource r = allocateResource(); 
try { 
    // use resource 
} 
finally { 
    r.dispose(); 
} 

Aktivitäten hier zu beachten:

  • versuchen und schließlich einen variablen Umfang jeder erstellen. Die Zuweisung Ihrer Ressource innerhalb der try-Klausel funktioniert also nicht, da sie in der finally-Klausel nicht sichtbar ist. Sie müssen die Variable der Ressource vor der try-Anweisung deklarieren.

Wenn Sie mehrere Ressourcen zuweisen, gilt das allgemeine Muster sauber, aber das ist oft nicht ersichtlich, für Anfänger:

Resource1 r1 = allocateResource1(); 
try { 
    // code using r1, but which does not need r2 
    Resource r2 = allocateResource2(); 
    try { 
     // code using r1 and r2 
    } 
    finally { 
     r2.dispose(); 
    } 
} 
finally { 
    r1.dispose(); 
} 

, und so weiter und so fort, wenn Sie mehr Ressourcen zuzuweisen . Wenn Sie ein paar von ihnen haben, werden Sie sicherlich versucht sein, zu vermeiden, tiefe Verschachtelung von versuchen ... endlich Aussagen. Nicht. Sie können Ressourcenfreigabe und Ausnahmebehandlung ohne Verschachtelung bekommen, so viele versuchen ... endlich Anweisungen, aber es richtig zu bekommen, ohne Verschachtelung versuchen ... schließlich ist noch hässlicher als tiefe Verschachtelung.

Wenn Sie häufig eine Reihe von Ressourcen nutzen, dann können Sie einen Funktor-basierte Methode implementieren, um die Wiederholung, so etwas wie zu vermeiden:

interface WithResources { 
    public void doStuff(Resource1 r1, Resource2 r2); 
} 

public static void doWithResources(WithResources withResources) { 
    Resource r1 = allocateResource1(); 
    try { 
     Resource r2 = allocateResource2(); 
     try { 
      withResources.doStuff(r1, r2); 
     } 
     finally { 
      r2.dispose(); 
     } 
    } 
    finally { 
     r1.dispose(); 
    } 
} 

die dann können Sie wie folgt verwenden:

doWithResources(new WithResources() { 
    public void doStuff(Resource1 r1, Resource2 r2) { 
     // code goes here 
    } 
}); 

doWithResources wird die Zuordnung und Freigabe automatisch richtig handhaben, und Ihr Code wird weniger Wiederholungen haben (was eine gute Sache ist). Allerdings:

  • Java-Syntax für anonyme Klassen übermäßig ausführliche
  • Checked Ausnahmen innerhalb doStuff Dinge komplizieren zu viel

, zwei Punkte, die ich hoffe, dass in Java 7 gelöst werden.

Sie diese Art von Code im ganzen Frühling, zum Beispiel finden:

+0

Danke, die Funktor-Sache sieht interessant aus. Zu schlecht gibt es keinen Zucker, um es zu vereinfachen. – drozzy

+0

Auch - meinst du nicht close() statt dispose()? Java hat eine Closeable-Schnittstelle. – drozzy

+0

"dispose" klang einfach generischer :-p. Es ist nur Pseudocode: -p – alex

1

Es gibt eine Alternative, um einen generischen Wrapper wie folgt aus:

final _<Item> item = new _<Item>(); 
final _<Connection> c = new _<Connection>(); 
with(factory, c, new Runnable() { 
    public void run(){ 
     item._ = c._.query(itemId); 
    } 
}); 
return item._; 

HINWEIS: Die Java Art und Weise ist, die Sie gerade beschrieben habe. Das andere ist nur für „Spaß“ und Experimentieren:

Die _ ist ein generischer Wrapper und die with Funktion ein Utility-Klasse definiert woanders als:

class WithUtil { 
    public static void with(ConnectionFactory factory, 
          _<Connection> c, Runnable block) { 
     try { 
      c._ = factory.getConnection(); 
      c._.open(); 
      block.run(); 
     } catch(Exception ioe){ 
     }finally{ 
      if(c._ != null) try { 
       c._.close(); 
      } catch(IOException ioe){} 
     } 
    } 
} 

In strengen Theorie, könnten Sie wieder -Nutzung es andere Sachen durchzuführen, wie ein Element zu löschen:

public void deleteItem(final int itemId) { 
     final _<Connection> c = new _<Connection>(); 
     with(factory, c, new Runnable() { 
      public void run(){ 
       Item item = c._.query(itemId); 
       if(! item.hasChildren()) { 
        c._.delete(item); 
       } 
      } 
     }); 
    } 

oder aktualisieren, es

public void update(final int itemId, String newName) { 
     final _<Connection> c = new _<Connection>(); 
     with(factory, c, new Runnable() { 
      public void run(){ 
       Item item = c._.query(itemId); 
       item.setName(newName); 
       c._.update(item); 
      } 
     }); 
    } 

Ohne den Versuch/Fang erneut integrieren zu müssen.

Hier ist ein full working demo, die das Konzept Beweise (und alles, was nicht tun)

+0

Was bedeuten die Unterstriche überall? Temporäre Variablennamen? – drozzy

+0

Das ist nicht Java (die Sprache), aber ich habe generische Klassen-Wrapper erstellt. Sie können es sich als einen * schlechten Pass durch Verweis * vorstellen. Es ist definiert als: 'class _ {public E _; } ': P – OscarRyz

+0

Sorry, ich bin mir immer noch nicht sicher, was Unterstriche sind. Sie sagen, dass sie nicht Teil der Java-Sprache sind ??? – drozzy