views:

208

answers:

9

I ran into this block of code today, and I don't know how it works. I know how to make anonymous classes, but I'm used to seeing a method signature and not just a pair of braces. Is the code between those braces put into a static block? Does it go into the constructor? Or is it something else altogether?

conext.checking(new Expectations() {
    { // <- what does this pair of braces do?
        oneOf(alarm).getAttackAlarm(null);
    }
});
A: 

It's an initializer block. I can't tell what it does without looking at the rest of the code.

The trick is to imagine "new Expectation()" replaced with "class Something extends Expectation".

DJClayworth
A: 

It limits the scope of any variables defined inside it. In this case there is no use for it. Perhaps the code inside it is generated so the code generator inserted the braces to make sure the variables didn't clash with any already defined.

samblake
Not true. In this case, it is more than just scope separation. Taking the brackets out would cause the code to not compile.
Milan Ramaiya
+6  A: 

It's an instance initializer that calls the code within with the context of the created object.

This is equivalent to

Expectations exp = new Expectations();
exp.oneOf(alarm).getAttackAlarm(null);
conext.checking(exp)

Whoever wrote it might have thought he was being more efficient by not declaring a variable (not true) or that it was cleaner code (I disagree).

The primary place that these initializers are useful like this is when instantiating maps, ie:

Map map = new HashMap() {{
  put("key1", "value1");   
  put("key2", "value2"); 
}};

which I think actually is slightly more readable.

Milan Ramaiya
It's called an "instance initializer", not a "static initializer" (the latter wouldn't have `this` for obvious reasons). Also see http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6
Pavel Minaev
It is not a static initializer, just an (instance) initializer. That block will be run *everytime* that code is run, not just the first time as would happen with a static initializer.
Mark Peters
Good note, I corrected that ....
Milan Ramaiya
That `Expectations` is actually pattern from jMock mocking library. Neat idea, but it's actually really confusing in the long run.
Esko
This specific example is, I believe, the recommended (by their documentation) way to do this in jMock 2. It does a lot to try to make test code written with it read fairly naturally.
ColinD
Readable, yes. But I find it absolutely abhorrent to do that (outside of test/scripting code anyway). It creates an extra class (and class file) for every map you create that way, taking up more permgen space, etc.
Mark Peters
Your "equivalent" example isn't. In the OPs code, the initialiser block (and, therefore, the `oneOf()` call) runs before any constructors. In your example, the (no-args) constructor runs before the `oneOf()` call.
dty
dty: Not true. I just made a test class to verify that. The constructor gets run before the initializer. Static initializers run before the constructor, but this isn't a static initializer.
Milan Ramaiya
A: 

What's happening ? The outer braces create a new anonymous class derived from Exception. The inner braces define an initialiser and sets the oneOf() etc.

Why do this ? It's a one-liner trick for constructing and initialising an instance of a class. e. you sometimes see something like this:

new Set<String>(){{add("one");add("two")}}

to initialise the contents of a collection.

Downsides ? Because you're creating an anonymous class within the containing class, that anonymous class contains a this reference to the outer class implicitly. Not normally a problem, but it can cause issues if (say) you want to serialise a class that you've constructed like this.

Brian Agnew
Not a *static* initializer.
DJClayworth
Ah. My bad. Corrected
Brian Agnew
+2  A: 

It is an initializer block, but not necessarily a static initializer block. It is effectively a constructor for an anonymous inner class. You will typically see this "double-brace initialization" pattern to conveniently create and populate collections:

private final Collection<Integer> FIXED_COLLECTION = Collections.unmodifiableCollection(new HashSet<Integer>() 
{ // first set of braces declares anonymous inner class
    { add(1); add(2); add(3); } // second set is initializer block
});
Outlaw Programmer
I have to say, in 15 years of Java programming, I've never come across an initialiser used like that before.
dty
+2  A: 

It's an instance initialiser (not a static initialiser).

Consider the definition of a class

public class Foo {
    private int i = getDefaultValue();

    private static int getDefaultValue() {
        return 5;
    }
}

The call to getDefaultValue() that initalises i is essentially a code block that runs each time an instance of Foo is constructed. The notation extends that function to allow more complex initialisation. E.g.

public class Foo {
    private int i;

    {
        int z = 4 + 5;
        i = z + getDefaultValue();
    }

    private static int getDefaultValue() {
        return 5;
    }
}

The manner with which it is used in JMock is a trick to give expectations the look of a closure construct.

Michael Barker
+1 for noting usage outside of anonymous classes. I also like the reference to closures! :-)
dty
+1  A: 

Anynoymous inner classes don't have a constructor, so you can define a an instance initilizer like this i.e. the inner set of braces are the instance initializers.

new Expectations() { 
    { 
        oneOf(alarm).getAttackAlarm(null); 
    }
}
Tingu
This syntax is not limited to anonymous classes. Although its use is unnecessary and confusing in a regular class.
dty
A: 

The java specification calls these blocks instance initializers, they are invoked by the constructor after the super constructor. You can define several of them and they will be executed in the order they occur in your code.

public class Test{
   public Test(){
       super();//Optional, inserted by the compiler
       //The initializers are executed here
       System.out.println("Third");
   }
   //Runs first since it is the first initializer block in the code
   {System.out.println("First");}
   //Runs after the first
   {System.out.println("Second");}
}

Java also has static initializers which are executed every time the class is loaded. These blocks are prefixed with static.

josefx
A: 

The primary motivation behind this, I believe, is to create a new name space, in which names defined in Expection can be referenced more easily.

For example, suppose java.lang.Math is not final,

new Math()
{{
    double x = sin(23.65);
    double y = log(x);
    ...
}};

It's almost as if we have something like

with names from Math
{
    double x = sin(23.65);
    double y = log(x);
    ...
}
irreputable