开发者

Java Syntactic Sugar

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 us开发者_StackOverflow社区ed 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);
    }
});


It's an instance initializer that calls the code within 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.


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


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.


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


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


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


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);
    ...
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜