Моделирование положения With Python в Java

Есть ли что-то как Python с менеджером по контексту в Java?

Например, скажите, что я хочу сделать что-то как следующее:

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;
8
задан Andriy Drozdyuk 31 May 2010 в 07:36
поделиться

3 ответа

На данный момент нет; Java до сих пор не добавила синтаксического сахара для этого шаблона. Тем не менее, он не будет таким чистым, как с (Python) или с использованием (C #), но вы можете хотя бы немного очистить это, просто вызвав c.close () внутри блока finally , а не дважды, как вы это делали:

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

Это также приводит его в соответствие с тем, как с и Фактически реализованы с использованием , которые представляют собой блок try..finally (а не try..catch ).

7
ответ дан 3 November 2019 в 13:08
поделиться

Как сказал цаман, секрет наконец используется; в общем:

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

Здесь следует отметить:

  • попробуйте и, наконец, каждый из них создает область видимости переменной. Таким образом, выделение вашего ресурса в предложении try не будет работать, поскольку оно не будет отображаться в предложении finally - вам нужно объявить переменную ресурса перед оператором try.

Если у вас есть несколько ресурсов для распределения, общий шаблон применяется чисто, но это часто не очевидно для новичков:

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, но получить все правильно без вложенности 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 для анонимных классов излишне подробен
  • Проверенные исключения в doStuff слишком усложняют ситуацию

, два момента, которые, я надеюсь, будут решены в Java 7.

Вы можете найти такой код в Spring, например:

3
ответ дан 3 November 2019 в 13:08
поделиться

Есть альтернатива, использующая универсальную оболочку вроде этой:

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

In строгой теории, вы можете повторно использовать ее для выполнения других задач, например, для удаления элемента:

    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.

Вот полная рабочая демонстрация , которая подтверждает концепцию (и больше ничего не делает)

1
ответ дан 3 November 2019 в 13:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: