0

重複の可能性:
Javaの匿名コードブロック

私は先日(SOで)それを学びました

public method() {
    someCode()
    {
        Object value = localCode();
        doSomethingWith(value);
    }
    moreCode();
}

有効なJavaであり、valueその領域にローカルを含むブロックを作成するためvalue、そのブロックにのみ存在します。

これの実用的な使い方はありますか?そうでない場合、なぜJavaはこの(ばかげた)使用について警告を出さないの{}ですか?

4

9 に答える 9

10

これは、さまざまなシナリオを繰り返したいテストで使用します。

{
    long start = System.nanoTime();
    // do something
    long time = System.nanoTime() - start;
    // print result.
}
{
    long start = System.nanoTime();
    // do something else
    long time = System.nanoTime() - start;
    // print result.
}
{
    long start = System.nanoTime();
    // do something else again.
    long time = System.nanoTime() - start;
    // print result.
}

これにより、名前を変更したり、変数を再利用したりすることなく、コードをコピーできます。

于 2012-08-15T14:22:19.817 に答える
3

これが実際の理由かどうかはわかりませんが、次の(やや工夫された)シナリオを想定してください。

public static void main(String[] args){
    int[] idsToCheck = {};
    {
       ExpensiveIDComputer sic = new ExpensiveIDComputer(); // very memory intensive call
       idsToCheck = sic.getIds();
    }
    // sic is now out of scope and can be GCed faster
    doManyOperationsOnIds(idsToCheck);
}

つまり、基本的には、メモリを大量に消費する操作をより高速にガベージコレクションできるようにすることができます。なぜ他の方法を使わないのか、私にはわかりませんが、これがあなたの質問を読んだときの私の最初の考えでした。

于 2012-08-15T14:24:12.450 に答える
1

...したがって、moreCodeはそのブロックのvalueの値のみを持ちます。

moreCodeブロック内で宣言されていない場合、これは正確には正しくありません。例えば:

int moreCode = 0;

{
    moreCode = 1;
    System.out.println(moreCode);
}

// Will print 1, not 0!
System.out.println(moreCode);

これを使用して、変数の範囲を制限できます。ブロック内で変数を宣言すると、その変数はブロック内にのみ存在します。

{
    int moreCode = 1;
    System.out.println(moreCode);
}

// Compile error: The variable moreCode doesn't exist here
System.out.println(moreCode);

ただし、これは一般的に使用されるものではありません。このようにスコープを制限するためにブロックを使用する必要があると思われる場合は、メソッドが複雑すぎる可能性があるため、ブロックをより単純なメソッドに分割することを検討する必要があります。

于 2012-08-15T14:23:07.867 に答える
1

私はこれを3つの理由で使用します:

  • ほとんどの場合、1つ以上の最終値を初期化しているときに、一時的な値を宣言/使用します。

    final int value;
    {
       final int counter;
       ... compute value ...
      value = counter;
    }
    
  • それ以外の場合は、外部名前空間に変数を導入せずに「機能する」(スコープを制限する)。

  • 一緒に属するコードのセクションを強調表示/区別するために、しかし私はまだ独立した​​方法に昇格する準備ができていません(一般的に全体の可読性のためにコードの局所性を維持するため)。[あらゆるユースケースの90%で、コードをプロモートする必要があります-これはやや例外的です]。

于 2012-08-15T14:46:42.130 に答える
1

いいえ、moreCode変数が{}ブロックの外部で宣言されたvalue場合、実行中に変更されない限り、変数は保持されます。

初期化ブロックはそれほど頻繁には使用されません。

ただし、クラスに複数のコンストラクターがある場合は便利です。コンストラクターは、変数の初期化やデータのロードなど、一般的な初期化操作を実行する必要があります。

以下に示すように、一般的なコンストラクタコードを初期化ブロックに貼り付けることができます。初期化ブロックは、コンストラクターと親コンストラクターの後にのみ実行されるという事実もあります。

インスタンス変数のイニシャライザーブロックは、静的イニシャライザーブロックと同じように見えますが、staticキーワードがありません。

{{

// whatever code is needed for initialization goes here 

}

Javaコンパイラは、初期化ブロックをすべてのコンストラクタにコピーします。したがって、このアプローチを使用して、複数のコンストラクター間でコードのブロックを共有できます。

参照:http ://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

于 2012-08-15T15:35:51.070 に答える
0

例としてはinstance initializers、コードが例外をキャッチする必要がある場合があります。

class SomeClass {
    private int myVar;

    // Instance initializer
    {
        try{ 
           myVar = getInitialValueFromDB(); 
        }  
        catch(Exception e){
           myVar = -1;
        }       
    }
    // no constructor here
    // ...
}
于 2012-08-15T14:23:43.047 に答える
0

コードブロックに名前を付けた場合は、名前をアドレス指定することbreakでブロックできます。

name1 : {
    name2 :{
        final int  i = 1;
        if( i == 1) {
            break name1;
        }
        System.out.println("name2");
    }
    System.out.println("name1");
}

することもできるlimit the scope of a variableので、ブロックの終了後、変数は簡単にgargabe-collectedできます。

于 2012-08-15T14:38:22.970 に答える
0

また、ラベルを追加してスパゲッティコードを作成することもできます!

MY_LABEL: {
  if (condition) {
    break MY_LABEL;
  }
  System.out.println("IN BLOCK");
}
System.out.println("OUTSIDE BLOCK");

trueの場合condition、制御フローは最初の印刷ステートメントをスキップし、2番目の印刷のみを取得します。

免責事項:スパゲッティコードの使用はお勧めしません。これは、そのようなブロックで何ができるかについての架空の議論にすぎません。

于 2012-08-15T14:39:51.307 に答える
0

別のユースケース:匿名サブクラスの最終変数を宣言します。明らかに、以下の匿名サブクラスで「foo」を参照することはできません。あなたはそれを「最終」にしなければならないでしょう。別の方法として、値を新しいfinal変数にコピーし、それを使用します。新しい変数は、実行中の特定の時点での「foo」のスナップショット値です。

int foo = 1;

....

{
  final int bar = foo;
  Future<Void> future = executorService.submit(new Callable<Void>() { // use bar here });
}

中かっこなしでこれを実行できることは理解していますが、これにより新しい変数の範囲が制限されます。

于 2012-08-15T15:25:03.287 に答える