Есть ли в Java оператор using?


108

Есть ли в Java оператор using, который можно использовать при открытии сеанса в спящем режиме?

В C # это примерно так:

using (var session = new Session())
{


}

Таким образом, объект выходит за рамки и автоматически закрывается.


4
«позволяя определить область действия объекта» Это не то, что usingнужно. Сфера - это не время жизни (и usingне время жизни, строго говоря, поскольку Disposeне разрушает память объекта)
Йорен

4
@Joren Ваш комментарий получает одобрение, но я мог бы добавить немного дополнительной информации. Вы тот, кто предлагает идею «жизни», тогда вы говорите, что она не о «продолжительности жизни». Область видимости - это термин, используемый в определении из библиотеки msdn, возможно, я неправильно его использовал. Как бы вы определили расширение using statement.
Jla

1
Область действия относится к области кода, в которой вы можете ссылаться на идентификатор, не используя его полное имя (локальная переменная, тип, имя метода и т. Д.). Время жизни - это время, в течение которого объект или переменная доступны. См blogs.msdn.com/b/ericlippert/archive/2009/08/03/...
Joren

2
Так, например, если у вас есть локальная переменная и вы назначаете ей экземпляр типа значения, то время жизни вашего значения закончится, когда закончится время жизни его переменной. Но если вы выделили объект и сохранили ссылку на него в локальном хранилище, то время жизни этого объекта вполне может превысить время жизни его хранилища, если еще есть ссылка на объект в другом месте. Что касается using, он автоматически удаляет объект в конце своей области видимости, но не освобождает объект - его время жизни не заканчивается, пока все его ссылки не исчезнут.
Joren

1
возможный дубликат ключевого слова using в java
HaveNoDisplayName

Ответы:


126

Java 7 представила автоматическое управление блоком ресурсов, которое переносит эту функцию на платформу Java. Предыдущие версии Java не имели ничего похожего using.

Например, вы можете использовать любую переменную, реализуемую java.lang.AutoCloseableследующим образом:

try(ClassImplementingAutoCloseable obj = new ClassImplementingAutoCloseable())
{
    ...
}

java.io.CloseableИнтерфейс Java , реализованный потоками, расширяется автоматически AutoCloseable, поэтому вы уже можете использовать потоки в tryблоке так же, как вы бы использовали их в usingблоке C # . Это эквивалентно C # using.

Начиная с версии 5.0, сеансы Hibernate реализуютсяAutoCloseable и могут быть автоматически закрыты в блоках ARM. В предыдущих версиях Hibernate Session не реализованAutoCloseable . Таким образом, вам нужно быть в Hibernate> = 5.0, чтобы использовать эту функцию.


1
«К счастью», поскольку сейчас доступна Java 7, этот ответ больше неверен (и я думаю, что блоки ARM - это именно то , что usingделает).
Иоахим Зауэр,

@ Йоахим Зауэр: Спасибо. Я обновил свой ответ, чтобы отразить время. На ваш взгляд, блоки ARM - это именно то, что делает using; в то время, когда я писал этот ответ, мне казалось, что блоки ARM должны быть блоками try, тогда как использование может применяться к любому произвольному блоку. Глядя на это сейчас, кажется, что ключевое слово do можно использовать в java для достижения этой цели. Было ли это добавлено в предложение недавно или я пропустил это в первый раз? Также OP спросил конкретно о сеансах гибернации. AFAIK: сеансы гибернации все еще не реализуются, AutoCloseableпоэтому они еще не могут использовать ARM.
Асаф

1
Событие Not в 4.3 Hibernate НЕ реализует AutoCloseable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/… Думаю, каждый может написать свою собственную оболочку?
Андрей Рыня

1
Сеанс не может реализовать AutoCloseable, поскольку Session.close () возвращает соединение. Я думаю, что это плохой дизайн, но я сомневаюсь, что когда-нибудь это будет изменено.
usr-local-ΕΨΗΕΛΩΝ

@ usr-local-ΕΨΗΕΛΩΝ Я просто подумал, что они обяжут всех, кто использует спящий режим, переключиться на java 7, если они реализовали этот интерфейс. AutoCloseableне существовало до Java 7 не так ли?
Нил

31

До Java 7 , не было нет такой функции в Java (для Java 7 и выше см Асафа ответ «s относительно ARM ).

Вам нужно было сделать это вручную, и это было больно :

AwesomeClass hooray = null;
try {
  hooray = new AwesomeClass();
  // Great code
} finally {
  if (hooray!=null) {
    hooray.close();
  }
}

И это просто код, когда // Great codeни hooray.close()одно исключение и не может выдавать никаких исключений.

Если вы действительно хотите ограничить только область видимости переменной, тогда простой блок кода выполнит свою работу:

{
  AwesomeClass hooray = new AwesomeClass();
  // Great code
}

Но, вероятно, вы имели в виду не это.


1
Эквивалент Java не должен вызывать проблем, если // Great codeвыдает исключение.
Cheeso

3
Когда конструктор выдает исключение, я думаю, ваш код приведет к исключению NullPointerException, которое маскирует исходное исключение.
Майкл Боргвардт

@Michael: на самом деле мой пример не будет компилироваться, потому что, horrayвозможно, не был инициализирован в этот момент (исправлено сейчас).
Иоахим Зауэр

4
+1 за плавающие простые блоки, которые могут ограничивать объем. Однако всякий раз, когда я их вижу, это почти всегда индикатор того, что метод следует разбить на более мелкие части.
Марк Питерс

1
если вы хотите перехватить какое-либо исключение из конструктора, вы должны поместить его в блок try. было бы обременительно обернуть все это в другую попытку / уловить.
чт


8

Технически:

DisposableObject d = null;
try {
    d = new DisposableObject(); 
}
finally {
    if (d != null) {
        d.Dispose();
    }
}

2
Не лучший способ это сделать. stackoverflow.com/questions/1909662/…
Марк Байерс

5
По сути, это было бы эквивалентно. Меня не волнует, лучший ли это способ.
ChaosPandion 06

2
Написано как настоящий программист на C #. ;)
Neil




2

Если вас интересует управление ресурсами, Project Lombok предлагает @Cleanupаннотацию. Взято прямо с их сайта:

Вы можете использовать, @Cleanupчтобы обеспечить автоматическую очистку данного ресурса до того, как путь выполнения кода выйдет из вашей текущей области. Вы делаете это, аннотируя любое объявление локальной переменной с помощью такой @Cleanup аннотации:

@Cleanup InputStream in = new FileInputStream("some/file");

В результате в конце области, в которой вы находитесь, in.close()вызывается. Этот вызов гарантированно запускается с помощью конструкции try / finally. Посмотрите на пример ниже, чтобы увидеть, как это работает.

Если тип объекта, который вы хотите очистить, не имеет close() метода, но имеет какой-либо другой метод без аргументов, вы можете указать имя этого метода следующим образом:

@Cleanup("dispose") org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent, 0);

По умолчанию предполагается, что это метод очистки close(). Метод очистки, который принимает аргумент, не может быть вызван через @Cleanup.

Ванильная Ява

import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        byte[] b = new byte[10000];
        while (true) {
          int r = in.read(b);
          if (r == -1) break;
          out.write(b, 0, r);
        }
      } finally {
        out.close();
      }
    } finally {
      in.close();
    }
  }
}

С Ломбоком

import lombok.Cleanup;
import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
  }
}


1

См. Этот Список ключевых слов Java .

  1. К usingсожалению, это ключевое слово не входит в список.
  2. И также нет эквивалента usingключевого слова C # никакому другому ключевому слову на данный момент в Java.

Чтобы имитировать такое "using"поведение, вам нужно будет использовать try...catch...finallyблок, в котором вы будете размещать ресурсы внутри finally.


6
Тот факт, что usingэто не ключевое слово, ничего не значит. Та же функция может быть (и будет!) Реализована с помощью другого ключевого слова, как упоминалось в @BalusC.
Иоахим Зауэр

1
Я согласен! Но пока его не существует, правда? Это то, что спросил ОП, было ли что-то подобное прямо сейчас. Приятно знать, что он будет в будущих выпусках, но на данный момент это так или иначе ничего не меняет. В любом случае, информация, предоставленная @BalusC, прекрасна! =)
Will Marcouiller

2
Я согласен с этим, но в вашем сообщении, похоже, говорится, что usingотсутствие в списке ключевых слов Java означает, что эта функция отсутствует в языке Java. А это неправда.
Иоахим Зауэр

Если это то, о чем, похоже, говорится в моем сообщении, я отредактирую его, чтобы отразить свое намерение.
Уилл Маркуллер

Я отредактировал свой ответ, указав, что не было ни usingключевого слова, ни эквивалента на данный момент. Спасибо, @Joachim Sauer! =)
Will Marcouiller


0

Чтобы ответить на вопрос об ограничении области действия переменной, вместо того, чтобы говорить об автоматическом закрытии / удалении переменных.

В Java вы можете определять закрытые анонимные области, используя фигурные скобки. Все очень просто.

{
   AwesomeClass hooray = new AwesomeClass()
   // Great code
}

Переменная hoorayдоступна только в этой области, а не за ее пределами.

Это может быть полезно, если у вас есть повторяющиеся переменные, которые являются временными.

Например, каждый с index. Так же, как itemпеременная закрывается в цикле for (т.е. доступна только внутри него), indexпеременная закрывается в анонимной области.

// first loop
{
    Integer index = -1;
    for (Object item : things) {index += 1;
        // ... item, index
    }
}

// second loop
{
    Integer index = -1;
    for (Object item : stuff) {index += 1;
        // ... item, index
    }
}

Я также иногда использую это, если у вас нет цикла for для предоставления области переменной, но вы хотите использовать общие имена переменных.

{
    User user = new User();
    user.setId(0);
    user.setName("Andy Green");
    user.setEmail("andygreen@gmail.com");
    users.add(user);
}

{
    User user = new User();
    user.setId(1);
    user.setName("Rachel Blue");
    user.setEmail("rachelblue@gmail.com");
    users.add(user);
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.