在Java中是否存在类似Python 和上下文管理器的内容?
例如说我想做类似以下的事情:
getItem(itemID){
Connection c = C.getConnection();
c.open();
try{
Item i = c.query(itemID);
}catch(ALLBunchOfErrors){
c.close();
}
c.close();
return c;
}
在python中我只有:
with( C.getConnection().open() as c):
Item i = c.query(itemID);
return i;
答案 0 :(得分:18)
Java 7引入了一项新功能来解决这个问题:“尝试使用资源”
http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Close resource quietly using try-with-resources
语法是将资源放在try关键字后的括号中:
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
在Java 7之前,您可以使用finally块。
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
答案 1 :(得分:6)
目前不在; Java仍然没有为这种模式添加语法糖。尽管如此,它不会像with
(Python)或using
(C#)一样干净,但你至少可以通过调用c.close()
来清理它。在finally
区块内,而不是你做过的两次:
try {
// use c
} finally {
c.close()
}
这也使它与with
和using
实际实现的方式一致,即try..finally
块(不是try..catch
)。
答案 2 :(得分:3)
正如特扎曼所说,秘密最终是在使用;一般:
Resource r = allocateResource();
try {
// use resource
}
finally {
r.dispose();
}
此处需要注意的事项:
如果要分配多个资源,一般模式应用得很干净,但这对初学者来说通常不明显:
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();
}
,依此类推,如果您有更多资源要分配。如果你有几个,你肯定会试图避免try ... finally语句的深度嵌套。别。您可以直接获得资源释放和异常处理,而无需嵌套这么多try ... finally语句,但是在没有嵌套的情况下正确尝试...最终甚至比深度嵌套更难。
如果您经常需要使用一组资源,则可以实现基于仿函数的方法以避免重复,例如:
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();
}
}
然后你可以像这样使用:
doWithResources(new WithResources() {
public void doStuff(Resource1 r1, Resource2 r2) {
// code goes here
}
});
doWithResources将自动正确处理分配和释放,并且您的代码将重复次数较少(这是一件好事)。但是:
,我希望在Java 7中解决两点。
你可以在整个Spring中找到这种代码,例如:
答案 3 :(得分:2)
答案 4 :(得分:1)
有一种替代方法可以使用这样的通用包装:
final _<Item> item = new _<Item>();
final _<Connection> c = new _<Connection>();
with( factory, c, new Runnable() {
public void run(){
item._ = c._.query( itemId );
}
});
return item._;
注意:Java方式是您刚才描述的方式。另一个只是为了“有趣”和实验:
_
是一个通用的包装器,with
函数是在其他地方定义的实用程序类:
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 ){}
}
}
}
在严格理论中,您可以重复使用它来执行其他操作,例如删除项目:
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 );
}
}
});
}
或更新
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 );
}
});
}
无需再次集成try / catch。
这是一个证明概念的full working demo(并且没有做任何其他事情)