Init Blocks will never haunt you again 👻!

android Aug 16, 2020

Never again be confuse 🤷  by init block in Kotlin, lets resolve which comes first egg(init) or chicken(constructor).

“awesomeandroid”

Koltin | init block | guess the code?-
Disclaimer : All the assets used as background belongs to respective companies I don't promote them as my own, they are just used to make code relatable and attractive.


Let's understand how it is performed In Java,

Guess the output #1 🕵🏻‍♂️ Java ☕️


class Guess{
    //can you guess the output??
    static{ System.out.print("1"); } // static block
    { System.out.print("2"); } // instance initialization block
    Guess(){ System.out.print("3");} // constructor
    { System.out.print("4"); }
    static{ System.out.print("5"); }
 }
 //options : a) 15243 b) 23415 c) 31524 d) 24153
Java | Guess output?

Correct Answer ✅

The right output is  15243.

To arrive to same the conclusion, you need to know some concepts of Java which are :

  1. Static block is executed when class is fully loaded by JVM. static members are owned by class not by instance. A class can have multiple static blocks, which will execute in the same sequence in which they have been written in the program.
  2. In Java, constructors always calls super() at the first line of execution and initializer blocks are moved just after super() call. A class can have multiple initializer blocks, which will execute in the same sequence in which they have been written in the program.
  3. Constructors are called with new operator .i.e one of its implementation is invoked when instance of the class is created.

Static Blocks 🧱

Static blocks are used to perform logic on the static fields of the class, most of the time it’s related to complex initialising of static fields before they are ready to be accessed into the main program, for instance :  

public static final Map<String, String> spiderman2021;
static {
    Map<String, String> cast = new HashMap<String, String>();
    cast.put("spiderman", "Tom Holland");
    cast.put("mayParker", "Marisa Tomei");
    cast.put("flashThompson", "Tony Revolor");
    // etc.
    spiderman2021 = Collections.unmodifiableMap(map);
}
Java | init block example

When to use Static block ❓

  • For classes whose constructor are not meant to be called but some computation is required in them i.e we need to do some action even if there is no instances.

class SpiderBeltUtil {
  
  private SpiderBeltUtil(){}
  
  final static int webShotsLimit ;
  
  static {
    int webShotBattery = // compute webshot battery
    int webCartrages = // compute web fluid remaining
    int webConsumptionRate = // compute webConsumption per shot 
    webShotsLimit = cartageCapacity + lastRemaingCartage + webShotBattery;
  }
}
Java | No Instance Class Example
  • You may wish to do something which should be shared by all objects of that class.

class Multiverse{
  private static isMultiverseSpiderManAlive = true;
  Multiverse getSpiderVerse(){}
}

Multiverse spiderVerse = new Multiverse();
System.out.println(spiderVerse.isMultiverseSpiderManAlive);
//output: true

Multiverse spiderVerseUltimate = new Multiverse();
System.out.println(spiderVerseUltimate.isMultiverseSpiderManAlive);
//output: true

------------------------------------------------------

class Multiverse{
  private static isMultiverseSpiderManAlive = true;
  
  static {
	spiderVerse.isMultiverseSpiderManAlive = vemonKillSpiderMan(/*isSuccess*/true);
  }
  
  Multiverse getSpiderVerse(){}
}

// In spiderVerse instance 
System.out.println(spiderVerse.isMultiverseSpiderManAlive);
//output: false

// In spiderVerseUltimate instance
System.out.println(spiderVerseUltimate.isMultiverseSpiderManAlive);
//output: false

Java | Shared Static init compute
  • For a Task which meant to be done only once per class, not be called every time an object is instantiated.

class IronSpiderSuitAnalytics {
  static boolean isAllowedToCollectData = false;
  static {
     isAllowedToCollectData = new remote().getIsSuitAnalyticsEnabled();
  }  
  public void syncData(){
      if(isAllowedToCollectData){
        //...send data to Avenger Servers
      }
  }
}
Java | action per class

Instance Initialization blocks (IIB) 🆕

Initialization blocks are used to perform logic on the data members of the class. You can initialize member variables or perform some extra operations.


private List<String> villans;
// Intializing blocks 
{
    villans = new ArrayList<>();
    villans.add("Venom");
    villans.add("Vulture");
    // etc.
}
Java | Instance initialising block example

When to use IIB❓

  • init blocks are useful to initialize final member variables

class IronSpiderSuit {
  final boolean spaceModeEnabled ;
  {
     spaceModeEnabled = sensorHeight > atmosphereHeight;
  }
  IronSpiderSuit(){
    System.out.println(spaceModeEnabled); // true|false but no error
  } 
}
Java | init final values
  • if you implement multiple constructors, then you need to repeat logic into same constructor. Using {} you can reduce repetition in all the constructors.

class SpiderMan {
  SpiderMan(String suit){
    getSpiderBelt();
    System.out.println(suit);
  } 
  
  SpiderMan(){
    getSpiderBelt();
    System.out.println("Red blue suit...");
  } 
}

//vs 

class SpiderMan {

  {getSpiderBelt();} 

  SpiderMan(String suit){
    System.out.println(suit);
  } 
  
  SpiderMan(){
    System.out.println("Red blue suit...");
  } 
}
Java | repetitions code smell
  • keeping constructor lean by removing DI (dependency injection) independent code outside of it.

class SpiderMan {
  SpiderBot spiderBot;
  SpiderTracker spiderTracker;
  EdihGlass edih;  
  SpiderMan(  EdihGlass edih ){
    this.edih = edih;
    SpiderBelt belt = new SpiderBelt();
    spiderBot = belt.getSpiderBot();
    spiderTracker = belt.getSpiderTracker();
  } 
}

//vs 

class SpiderMan {
  SpiderBot spiderBot;
  SpiderTracker spiderTracker;
  EdihGlass edih;  
  
  {
    //independent from DI (dependency injection)
    SpiderBelt belt = new SpiderBelt();
    spiderBot = belt.getSpiderBot();
    spiderTracker = belt.getSpiderTracker();
  }
  
  SpiderMan(EdihGlass edih ){
    this.edih = edih; // DI (dependency injection)
  } 
}
Java | lean constructor

TLDR 📝

Java Block invoke
Static block Runs once(when the class is initialized)
Instance Initialization block Runs each time you instantiate an object | DI independent code
constructor Runs each time you instantiate an object | DI dependent code

Guess the output #2 🕵🏻‍♂️ Kotlin 💻

Now lets explore a similarly example in the Kotlin,

class Guess{
    //can you guess the output??
    val value1 = "1".also{print(it)} // data member
    init{ print("2") } // init block
    val value2 = "3".also{print(it)} // data member
    init{ print("4") } 
    constructor(){ print("5")} // constructor
    companion object {
      // companion object
        init{ print("6") } 
        val value3 = "7".also{print(it)} 
        init{ print("8") } 
        val value4 = "9".also{print(it)}
   }
}
 
  //options : a) 678912345 b) 687924135 c) 796813245 d)1234567
  
Kotlin | Guess the output?

Correct Answer ✅

The right output is  678912345`.

In Kotlin, Constructor are of two types primary and secondary.

  • The primary constructor is part of the class header, main limitation with primary constructor is that it doesn't have a body i.e cannot contain code and constructor keyword is optional for it unless we explicitly specify visibility modifier. Secondary constructor always starts with constructor keyword, secondary constructor needs to delegate to the primary constructor, either directly or indirectly.
  • Init block can be used to write initialization code for primary constructor , all initializer blocks and property initializers are executed before the secondary constructor's body. A class can have multiple init blocks, which will execute in the same sequence in which they have been written in the program. From this you can make out init block and IIBs in java are same in behaviour.
  • Companion Object are used to create property which will be tied to a class rather than to instances .i.e Static members. A companion object is initialized when the class is loaded. Init block inside of companion object is similar to static block. A companion object can have multiple init block , which will execute in the same sequence in which they have been written in the program.

TLDR 📝

Java Kotlin
Static block Companion init block
Instance Initialization block init block
constructor Primary or Secondary constructor

With this you understand the basic mapping of Kotlin with Java , now you can scroll back up and read through again what all places you can use init blocks, companions init block and constructors.


Extra : Companion Objects 👩‍💻

As told above companion objects are used to create properties tied to class rather than instance, a companion object is an object itself, which is Kotlin's singleton pattern implementation, companion object can have their supertypes and there could be only one companion object in a class.


class SpiderMan : Venom() {
    // companion can be extended
    init { println("iSpidy")}    
    companion object : Factory<Venom> {
        init { println("OSpidy")}  
        override fun getInstance(): Venom {
            return SpiderMan()
        }
    }
}

interface Factory<T> {
    fun getInstance(): T
}

// does this affect init block call? NO

// can we have init block in interface ? NO , because interface don't 
// have constructors

// what about abstract class? YES, example
abstract class Venom {
  init { println("iVenom")}
  companion object {
    init { println("OVenom")}
  }
}

// Output 
// OVenom // base static
// OSpidy // child static
// iVenom // base init
// iSpidy // child init
Kotlin | Companion object Example

Conclusion 💆🏻‍♀️

With this you would be clear how init block and constructor are invoked, plus some places you would like to consider them.

That's all for today 💻 ! see ya again in next article. Peace!✌


Enjoy the article?

a clap is much appreciated if you enjoyed. No sign up or cost associated :)




Chetan gupta

Hi there! call me Ch8n, I'm a mobile technology enthusiast! love Android #kotlinAlltheWay, CodingMantra: #cleanCoder #TDD #SOLID #designpatterns

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.