Чи має у Java заяву використання?


107

Чи має Java-заяву, яке можна використовувати під час відкриття сеансу в сплячому режимі?

У 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, він автоматично розпоряджається об’єктом наприкінці його обсягу, але не розставляє об'єкт - його термін експлуатації не закінчився, поки всі його посилання не зникли.
Джорен

Відповіді:


124

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 Sessions реалізуютьсяAutoCloseable та можуть бути автоматично закриті в блоках ARM. У попередніх версіях сплячого засідання не застосовувавсяAutoCloseable . Тож вам потрібно буде перебувати в режимі глибокого сну>> 5.0, щоб використовувати цю функцію.


1
"На щастя", з Java 7 тепер доступна, ця відповідь вже не відповідає дійсності (і я думаю, що блоки ARM - це саме те , що usingробить).
Йоахім Зауер

@Joachim Sauer: Дякую Я оновив свою відповідь, щоб відобразити минулий час. На ваш погляд, ARM-блоки є саме тим, що використовує; на той момент, коли я писав цю відповідь, мені здавалося, що блоки ARM повинні бути пробними блоками, тоді як використання може застосовуватися до будь-якого довільного блоку. Дивлячись на це зараз, здається, ніби ключове слово ja може бути використане в Java для цього. Це було додано до пропозиції нещодавно чи я пропустив її вперше? Також ОП запитала спеціально про сплячі сесії. AFAIK: Зимові сплячки все ще не застосовуються, AutoCloseableтому вони ще не можуть використовувати ARM.
Асаф

1
Не подія в 4.3 . Спячий режим НЕ реалізує функцію автоматичного закриття. 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
якщо ви хочете вилучити будь-який виняток з конструктора, ви повинні мати його всередині блоку спробу. було б громіздко загорнути всю справу в іншу спробу / улов.
тис


8

Технічно:

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

2
Не найкращий спосіб це зробити. stackoverflow.com/questions/1909662/…
Марк Байерс

5
Це по суті було б рівнозначно. Мені все одно, чи це найкращий спосіб.
ChaosPandion

2
Написаний як справжній програміст C #. ;)
Ніл




2

Якщо ви зацікавлені в управлінні ресурсами, Project Lombok пропонує @Cleanupпримітку. Взяті безпосередньо з їх сайту:

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

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

Як результат, в кінці області, в якій ви перебуваєте, in.close()викликається. Цей виклик гарантовано виконується шляхом спроби / нарешті побудови. Подивіться на приклад нижче, щоб побачити, як це працює.

Якщо тип об'єкта, який ви хочете очистити, не має close() методу, а якогось іншого методу без аргументів, ви можете вказати ім'я цього методу так:

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

За замовчуванням вважається метод очищення close(). Метод очищення, який приймає аргументи, не можна викликати через @Cleanup.

Ванільна Java

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, чудова! =)
Буде Маркуйлер

2
Я погоджуюся з цим, але ваш пост, схоже, говорить про те, що факт usingвідсутності у списку ключових слів Java означає, що ця мова відсутня в мові Java. І це неправда.
Йоахім Зауер

Якщо так видається моя публікація, я редагую, щоб відобразити свій намір.
Буде Маркуйлер

Я відредагував свою відповідь, вказавши, що немає usingключового слова та жодної еквівалентності, як зараз. Дякую @Joachim Sauer! =)
Буде Маркуйлер


0

Щоб відповісти на питання щодо обмеження області змінної, замість того, щоб говорити про автоматичне закриття / розміщення змінних.

На Java ви можете визначити закриті, анонімні області застосування за допомогою фігурних дужок. Це надзвичайно просто.

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

Змінна hoorayдоступна лише в цій області, а не поза нею.

Це може бути корисно, якщо у вас є повторювані змінні, які є лише тимчасовими.

Наприклад, кожен з індексом. Так само, як 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
    }
}

Я також використовую це іноді, якщо у вас немає циклу для надання змінної області, але ви хочете використовувати загальні імена змінних.

{
    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.