2010-05-31 10 views
6

Esiste qualcosa come Python con il gestore contesto in Java?Simulazione di python Con istruzione in java

Per esempio dicono che voglio fare qualcosa di simile al seguente:

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

    c.close(); 
    return c; 
} 

dove in python devo solo:

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

Non conosco molto bene 'with' o Python, ma se è qualcosa di simile a' uso di C#, questo è stato risolto molto recentemente: http://stackoverflow.com/questions/ 2943542/using-keyword-in-java –

+0

+1 ma: '[const]' '[final]' esiste anche, quindi '[with]' dovrebbe avere anche un tag. Non riesco ancora a crearlo. – n611x007

risposta

5

Non al momento; Java non ha ancora aggiunto zucchero sintattico per questo modello. Ancora, non sarà pulito come with (Python) o using (C#), ma puoi almeno ripulirlo un po 'semplicemente avendo una chiamata a c.close() all'interno di un blocco finally, invece del doppio che hai fatto:

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

Questo porta anche in linea con quanto sia with e using sono in effetti implementate, che è un blocco try..finally (non un try..catch).

+0

Grazie ... I guest potrei anche usare un modello di metodo template, che richiede una gerarchia di classi brutta. Saluti. – drozzy

3

Come disse lo tzaman, il segreto sta usando finalmente; in generale:

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

cose da notare qui:

  • prova e, infine, creare un ambito di ciascuna variabile. Quindi allocare la tua risorsa all'interno della clausola try non funzionerà, in quanto non sarà visibile nella clausola finally- devi dichiarare la variabile della risorsa prima dell'istruzione try.

Se si dispone di diverse risorse da allocare, lo schema generale si applica in modo pulito, ma questo spesso non è evidente per i principianti:

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(); 
} 

, e così via e così via, se si dispone di più risorse per allocare . Se ne hai un paio, sarai sicuramente tentato di cercare di evitare il nidificazione profonda delle affermazioni try ... finally. Non farlo. È possibile ottenere la deallocazione delle risorse e la gestione delle eccezioni a destra senza nidificare così tante provate ... finalmente le affermazioni, ma facendolo correttamente senza provare il nidificazione ... finalmente è ancora più brutto del nidificazione profonda.

Se avete spesso bisogno di utilizzare un insieme di risorse, è possibile implementare un metodo funtore-based per evitare la ripetizione, qualcosa come:

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(); 
    } 
} 

Che poi si può usare in questo modo:

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

doWithResources gestirà automaticamente l'allocazione e la deallocazione correttamente e il codice avrà meno ripetizioni (che è una buona cosa). Tuttavia:

  • la sintassi di Java per le classi anonime è eccessivamente verbose
  • eccezioni verificata entro doStuff complicare troppo le cose

, due punti che mi auguro possa essere risolto in Java 7.

È possibile trovare questo tipo di codice durante primavera, per esempio:

+0

Grazie, la cosa del functor sembra interessante. Per il male non c'è zucchero per semplificarlo. – drozzy

+0

Inoltre, non intendi close() invece di dispose()? Java ha un'interfaccia Closeable. – drozzy

+0

"dispose" appena suonato più generico :-p. È solo pseudocodice :-p – alex

1

C'è un'alternativa utilizzando un wrapper generico come questo:

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

NOTA: Il modo in cui Java è quella che ho appena descritto. Questo altro è solo per "divertimento" e sperimentazione:

Il _ è un wrapper generico e la funzione with è una classe di utilità definita da qualche altra parte come:

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 rigorosa teoria, si potrebbe ri -utilizzare per eseguire altre cose, come l'eliminazione di un elemento:

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); 
       } 
      } 
     }); 
    } 

o aggiornarlo

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); 
      } 
     }); 
    } 

Senza dover integrare nuovamente il try/catch.

Ecco un full working demo che rende impermeabile il concetto (e non fa altro)

+0

Cosa significano i caratteri di sottolineatura ovunque? Nomi di variabili temporanee? – drozzy

+0

Non è Java (la lingua), ma ho creato un wrapper di classe generico. Potresti pensarlo come un * passaggio scadente per riferimento * sostituto. È definito come: 'classe _ {public E _; } ': P – OscarRyz

+0

Siamo spiacenti, non sono ancora sicuro di quali caratteri di sottolineatura siano. Stai dicendo che non fanno parte della lingua java ??? – drozzy