What is the use of nested blocks in Java?

Asked

Viewed 640 times

10

I saw something written similar to the code below. That second block in the method method has any utility? It has to be used somehow?

I ran this code and it compiled and appeared only the message First print., not presenting Second print..

I’ve seen something like Try...catch...Finally, but this is not the same case.

If it can be used in any way, someone will write me a practical example?

public class BlocoAninhado {

    public static void main(String[] argumentos) {
        BlocoAninhado.metodo();
    }

    public static void metodo() {
        System.out.println("Primeiro print.");
    }

    {
        System.out.println("Segundo print.");
    }
}

3 answers

8


The example block you gave is a Instance Initializer with purpose other than a simple block of scope. Whenever you find these loose blocks within the body of a class, it comes to that and not the variable scope blocks.

A brother of Instance Initializer is the Static Initializer:

public class BlocoAninhado {

    public static void main(String[] argumentos) {
        BlocoAninhado.metodo();
    }

    public static void metodo() {
        System.out.println("Segundo print.");
    }

    static {
        System.out.println("Primeiro print.");
    }
}

It must execute, and the block of its example does not execute because an instance of that class is not created. The Static Initializer executes because it is not bound to the instance, as well as any static method.

The other case of loose blocks are the common ones you find within the functions, these are scope blocks. A common and useful use of them is in cases of command switch:

switch(foo) {
  case BAR: {
    int x;
  }
  break;

  case BAZ: {
    char x; //usando o mesmo nome sem problemas.
  }
  break;
}

For illustration, this would make the type of block you are using run:

public class BlocoAninhado {

    public static void main(String[] argumentos) {
        (new BlocoAninhado()).metodo();
    }

    public static void metodo() {
        System.out.println("Segundo print.");
    }

    {
        System.out.println("Primeiro print.");
    }
}
  • It would be if it were a class without main. Then it would be exactly one Instance Initializer.

  • 2

    @Felipeavelar is still a Instance Initializer the fact that you have a main it does not matter, what happens is that as there is created a de facto instance of this class, a Instance Initializer is not called, if it were a Static Initializer would be.

3

Java blocks have multiple applications

Body of classes and methods

Class:

class C { ... }

Method:

void m() { ... }

Implementations inline:

Runnable r = new Runnable() {
    public void run() { ... }
};

Group statements into conditional, ties and exceptional control

Conditional:

if (cond) { ... } else { ... }
switch (valor) { case 1: ...; break; default: ...}

Ties:

while (cond) { ... }
do { ... } while (cond)
for (...) { ... }

Exceptional control and closure:

try { ... } catch { ... } finally { ... }

Arbitrary blocks

They are placed in the middle of the code and follow the normal flow of execution, but with their own scope, which means that the declared variables will no longer exist at their closure.

int a = 1;
{
    int b = a + 2; //b == 3
}
//b não existe mais

This is probably allowed by a language question, that is, a block can replace a valid command in Java grammar. This greatly simplifies implementation because the compiler does not need to do a special check to allow blocks only in specific commands.

Labels

It is possible to use the command break <label> to interrupt the execution of a specific block.

I couldn’t think of any practical application, so go an example without the slightest sense anyway:

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 constructor):

classe C {
    { ... }
}

Static (executes when class is loaded on first use:

classe C {
    static { ... }
}

The order of execution

An interesting question about the boot 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:

  1. init main: the first item is from the method main, soon the subclasses were not initialized.
  2. static initializer A: when executing new B() Java first executes the static initializer of the Parent class.
  3. y(static A): then the static attribute y class A was initialized.
  4. y(static B): then the static attribute y class B was initialized.
  5. static initializer B: now, yes the static initializer of B.
  6. y(instance A): now the instance attribute y2 class A.
  7. instance initializer A: now the class instance initializer A.
  8. constructor A: and the builder of A.
  9. y(instance B): now the instance attribute y2 class B.
  10. instance initializer B: and the instance initializer of B.
  11. constructor B: ending the boot sequence, Java runs the constructor of B.
  12. imprime(): and the instance method is called.
  13. end main: finally the method main ends.

Based on this, we can say that the execution order is:

  1. Static variables and initializers, starting from the parent class and ending from the daughter, and the order in which they are declared in the body of each hierarchy class.
  2. Starting again in the parent class and ending in the daughter, initialization of instance variables, instance initializers and constructors are executed in this order.

2

This is mainly used to declare that a variable belongs only to that scope. For example:

public class Teste{

  public static void main(String[] args){
    Teste.imprime();
  }

  public static void imprime(){
    {
      int i = 0;
      System.out.println(i);
    }
    {
      int i = 2;
      System.out.println(i);
    }
  }
}

You will be able to compile successfully and will have as output:

0
2

However, if you reverse, for example, the order of the lines in the second block:

public class Teste{

  public static void main(String[] args){
    Teste.imprime();
  }

  public static void imprime(){
    {
      int i = 0;
      System.out.println(i);
    }
    {
      System.out.println(i);
      int i = 2;
    }
  }
}

You will receive the following, for this code, the following build error:

Teste.java:13: error: cannot find symbol
                        System.out.println(i);
                                           ^

That is, it serves as a very primary form of encapsulation, restricting access only to the block she belongs to.

  • 2

    In the question example the block appears outside any function, in the scope of the class.

  • Actually the extra line was put in by Netbeans @Guilhermebernal. Very good Felipe, thank you.

  • @Garoudan is sure that this is not the case with the answer I gave. They are very different things.

  • @Guilhermebernal, I put inside the other, because if you try to run the proposed example, it will only run the first print.

  • 1

    @Felipeavelar It turns out, the question has a layman’s tone of someone who saw something and does not know what it is. You did not answer about the given code, and the description given is vague, but the code is valid, you at the end gave an answer based on an assumption that does not derive from the given code, which may indeed be what the OP has seen around.

  • @pepper_chico I agree that this may have happened, but still I can assume that the code that the OP saw would be similar to my assumption (I’m not saying that neither I or you are wrong)but the fact of not instantiating the object is what most draws my attention to not being a Instance Initializer (besides the fact that it is not usual, although possible, to instantiate the class itself with a main), this set of characteristics led me to my assumption, as the absence of keys led you to assume that it was a Instance Initializer.

  • So it looks like it’s another case anyway. I’ll take a look @pepper_chico.

  • @Garoudan at ease =)

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.