Java blocks have multiple applications
Body classes and methods
Class:
class C { ... }
Method:
void m() { ... }
Inline implementations:
Runnable r = new Runnable() {
public void run() { ... }
};
Group declarations in conditionals, loops, and exceptional control
Conditional:
if (cond) { ... } else { ... }
switch (valor) { case 1: ...; break; default: ...}
Ties:
while (cond) { ... }
do { ... } while (cond)
for (...) { ... }
Exceptional control and shutdown:
try { ... } catch { ... } finally { ... }
Arbitrary Blocks
They are placed in the middle of the code and follow the normal flow of execution, but with a scope of their own, which means that the declared variables will no longer exist at closing.
int a = 1;
{
int b = a + 2; //b == 3
}
//b não existe mais
This is probably allowed for a language issue, that is, a block can replace a valid command in Java grammar. This greatly simplifies the implementation because the compiler does not need to perform a special check to allow blocks only in specific commands.
Labels
You can use the break <label>
command to stop execution of a specific block.
I have not been able to think of any practical application, so here's an example without even the slightest sense:
int a = 1;
myLabel: {
for (int i = 0; i < 20; i++) {
a++;
if (a == 5) {
break myLabel;
}
}
System.out.println("Não vai imprimir isso!");
}
System.out.println(a);
Instance and class initializers
Instance (runs before builder):
classe C {
{ ... }
}
Static (executes when class is loaded on first use:
classe C {
static { ... }
}
The order of execution
An interesting question about the initialization blocks is about the order in which they are executed, whereas there is the object constructor and attribute initializations.
Consider the following example:
public class Initializations {
static class X {
static int y(String str) {
System.out.println("y(" + str + ")");
return 1;
}
}
static class A {
static {
System.out.println("static initializer A");
}
static int y = X.y("static A");
int y2 = X.y("instance A");
{
System.out.println("instance initializer A");
}
public A() {
System.out.println("constructor A");
}
}
static class B extends A {
static int y = X.y("static B");
int y2 = X.y("instance B");
static {
System.out.println("static initializer B");
}
{
System.out.println("instance initializer B");
}
public B() {
System.out.println("constructor B");
}
public void imprime() {
System.out.println("imprime()");
}
}
public static void main(String[] args) {
System.out.println("init main");
new B().imprime();
System.out.println("end main");
}
}
I will comment on the result produced by the above code:
init main
: the first item is of method main
, so the subclasses were not initialized.
static initializer A
: when executing new B()
Java executes the static parent initializer of the parent class first.
y(static A)
: then the static attribute y
of class A
was initialized.
y(static B)
: then the static attribute y
of class B
was initialized.
static initializer B
: now, yes the static initializer of B
.
y(instance A)
: now the instance attribute y2
of class A
.
instance initializer A
: now the instance initializer of class A
.
constructor A
: and the A
constructor.
y(instance B)
: now the instance attribute y2
of class B
.
instance initializer B
: and the instance initializer of B
.
constructor B
: ending the initialization sequence, Java executes the constructor of B
.
imprime()
: and the instance method is called.
end main
: finally the main
method ends.
Based on this, we can say that the order of execution is:
Static variables and initializers, starting from the parent class and ending with the child, and in the order they are declared in the body of each class in the hierarchy.
Beginning once again in the parent class and ending in the child, instantiation initializers, instance initializers, and constructors are executed in this order.