Имитация Python с утверждением в Java - PullRequest
7 голосов
/ 31 мая 2010

Есть ли что-то вроде 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;

Ответы [ 5 ]

18 голосов
/ 02 апреля 2013

Java 7 представила новую функцию для решения этой проблемы: «попробуй с ресурсами»

http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

Тихо закрывать ресурс с помощью 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();
}
6 голосов
/ 31 мая 2010

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

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

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

3 голосов
/ 31 мая 2010

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

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, но понимая их правильно, не пытаясь выполнить ... 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, например:

2 голосов
/ 14 декабря 2015

try-with-resources был представлен в Java 7. До этого вам приходилось использовать блоки try-finally. Смотри документацию здесь: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

1 голос
/ 31 мая 2010

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

 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.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...