Javaにはusingステートメントがありますか?


107

Javaには、休止状態でセッションを開くときに使用できるusingステートメントがありますか?

C#では次のようになります。

using (var session = new Session())
{


}

そのため、オブジェクトはスコープ外になり、自動的に閉じます。


4
「オブジェクトのスコープを定義できるようにする」それはそうでusingはありません。スコープは(と寿命ではないusingとして、厳密に言えば、どちらかの寿命に関するものではありませんDispose、オブジェクトのメモリを破壊しない。)
Joren

4
@Jorenあなたのコメントは賛成投票されていますが、もう少し情報があればできるでしょう。あなたは「生涯」のアイデアを紹介している人であり、それは「生涯」ではないということです。スコープとは、msdnライブラリの定義で使用されている用語です。誤用している可能性があります。どのように定義しますかusing statement
Jla

1
スコープとは、完全修飾名(ローカル変数、タイプ、メソッド名など)を使用せずに識別子を参照できるコード内の領域を指します。ライフタイムとは、オブジェクトまたは変数にアクセスできる時間を指します。blogs.msdn.com/b/ericlippert/archive/2009/08/03/を
Joren

2
したがって、たとえば、ローカル変数があり、それに値型インスタンスを割り当てる場合、変数のライフタイムが終了すると、値のライフタイムも終了します。しかし、オブジェクトを割り当てて、それへの参照をローカルに保存した場合、そのオブジェクトへの参照が他の場所にまだある限り、そのオブジェクトの存続期間は、そのストレージの存続期間を超えて非常に長く延びる可能性があります。については、スコープの最後にオブジェクトをusing自動的に破棄しますが、オブジェクトの割り当てを解除しません。すべての参照が消えるまで、オブジェクトの寿命は終了しません。
Joren

回答:


124

Java 7 では、この機能をJavaプラットフォームにもたらす自動リソースブロック管理が導入されました。以前のバージョンのJavaには類似点はありませんでしたusing

例として、java.lang.AutoCloseable次の方法で実装する任意の変数を使用できます。

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

java.io.Closeableストリームによって実装されるJavaのインターフェースは自動的に拡張されるAutoCloseableためtry、C#usingブロックで使用するのと同じように、ブロックでストリームを既に使用できます。これはC#と同等usingです。

以下のようにバージョン5.0、休止セッションが実装AutoCloseableとARMブロックで自動閉鎖することができます。以前のバージョンのHibernate SessionAutoCloseableでは、は実装されていませんでした。したがって、この機能を使用するには、Hibernate> = 5.0を使用する必要があります。


1
「幸運なことには、」Javaの7は現在入手可能であるとともに、この答えは、もはや真ではない(と私はARMブロックが考える丁度あるものをusing行います)。
ヨアヒムザウアー

@ヨアヒムザウアー:ありがとうございます。時間の経過を反映するように回答を更新しました。ARMブロックは、正確にはusingと同じです。私がこの回答を書いたとき、ARMブロックはtryブロックでなければならないように見えましたが、使用は任意のブロックに適用できます。今それを見ると、Javaでdoキーワードを使用してこれを実現できるようです。それは最近提案に追加されましたか、それとも初めて見逃しましたか?また、OPはHibernateセッションについて具体的に尋ねました。AFAIK:Hibernateセッションはまだ実装されていないAutoCloseableため、まだARMを使用できません。
Asaph 2011

1
4.3 Hibernateのイベントではない AutoCloseableを実装していませんdocs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/…独自のラッパーを作成するのは誰でもできると思いますか?
AndreiRînea2013年

1
Session.close()が接続を返すため、セッションはAutoCloseableを実装できません。これは悪いデザインだと思いますが、今後変更されることはないと思います。
USR-ローカルΕΨΗΕΛΩΝ

@usr-local-ΕΨΗΕΛΩΝ彼らがそのインターフェースを実装している場合、彼らがhibernateを使用してjava 7に切り替えることを誰かに義務付けているだろうと私は考えました。 AutoCloseableJava 7以前は存在しませんでしたか?
Neil

31

Java 7以前は、Javaそのような機能はありませんでした(Java 7以降については、ARMに関するAsaphの回答を参照してください))。

あなたはそれを手動で行う必要があり、それは苦痛でした

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
// Great code例外がスローされても、Javaの同等の機能で問題はないはずです。
Cheeso

3
コンストラクターが例外をスローすると、コードによって、元の例外をマスクするNullPointerExceptionが発生すると思います。
Michael Borgwardt、

@Michael:horrayその時点で初期化されていない可能性があるため、実際には私の例はコンパイルされません(現在修正済み)。
Joachim Sauer

4
スコープを制限できる単純なフローティングブロックの+1。ただし、これらを見ると、ほとんどの場合、メソッドが小さなチャンクに分割される必要があることを示しています。
Mark Peters、

1
コンストラクターからの例外をキャッチする場合は、tryブロック内に例外を置く必要があります。すべてを別のtry / catchでラップするのは面倒です。
2014






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、現在のJavaのように、他のキーワードによるC#キーワードの同等性もありません。

このような"using"動作を模倣するには、try...catch...finallyブロックを使用する必要がありますfinally。このブロックでは、内のリソースを破棄します。


6
実際usingのキーワードではない事を意味するものではありません。@BalusCが言及したように、同じ機能を別のキーワードで実装できます(実装されます!)。
Joachim Sauer

1
同意する!でも今のところ存在しませんね。ちょうど今何か似ているものがあったかどうか、それはOPが尋ねたものです。それが将来のリリースで存在することを知っておくのは良いことですが、それは今のところ、何かを変えることはありません。とにかく、@ BalusCが提供する情報は素晴らしいです。=)
Will Marcouillerが2010年

2
私はそれに同意しますが、あなたの投稿はusing、Javaキーワードのリストに含まれていないという事実は、この機能がJava言語に存在しないことを意味すると言っているようです。そして、それは真実ではありません。
Joachim Sauer

これが私の投稿のように思われる場合は、私の意図を反映するように編集します。
Marcouillerが

今のところ、usingキーワードはなく、同等もないように私の回答を編集しました。@Joachim Sauerに感謝します!=)
Will Marcouillerが2010年


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

変数スコープを提供するための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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.