Thursday, June 11, 2009

Initializer Blocks & their alternatives in Java


Initializer Blocks in Java and their possible alternatives

Initializer Blocks - what are they, why & how are they used?


These blocks are similar to the static initialization blocks with the only difference being the absence of the 'static' keyword. The Java compiler copies all the initializer blocks in the same order as they are in the source code in every constructor before any executable statement in that constructor.



public class InitializationWithInitializerBlock{

public static int staticIntField = 100;
private boolean instanceBoolField;

{
boolean y;

y = true; //or, y = <some expression returning a boolean value>;

instanceBoolField = y;
}
}


So if you see all your constructors having same code-segment at the top then you will probably be better off keeping that in an initializer block as anyway the compiler would copy the block in every constructor at the top. This way you can at least make the code more readable, maintainable (as the common code will only be at one place), and if the size of common code is significant and if you have multiple constructors then using initializer block you can also reduce the size of your source code.


public class InitializerBlocks {

public static void main(String[] args) {
new InitializerBlocks();
}
//Constructor - 1
public InitializerBlocks(){
System.out.println("3");
}
//Initializer Block - 1
{
System.out.println("1");
}
//Initializer Block - 2
{
System.out.println("2");
}
}

Output

1
2
3

(Of course the above code is not making a good use of initializer blocks as they not initializing anything what they are actually meant to. The purpose here is just to show how a Java compiler places all the initializer blocks at the top in every constructor in the same order as they appear in the code.)

Alternative to Initializer Blocks in Java


You can use an instance method to initialize an instance field - in most of the cases you would like to make this instance method as 'final' as there will hardly be any need for the subclasses to override such a method (evidently, a non-final instance method would also do the job). Similarly if you need to call the method only from within the same class, you would probably make it 'private'.
Read more about how to pick access modifiers - choosing suitable access control modifiers in Java >>


public class InitializationWithPrivateInstanceMethod{

public static int staticIntField = 100;
private boolean instanceBoolField = privInstanceMeth();

private final boolean privInstanceMeth() {
boolean y;
//computing the value of y
y = <some expression returning boolean>;
return y;
}
}


The advantage of using an instance method over an initializer block is that it gives you flexibility of re-initializing those instance fields by calling the corresponding final instance method(s) in some setter or in some other method. Another interesting scenario where you can't use an initializer block and you would probably need an instance method to do it for you: Suppose you have a need of using the code of initializer block in any of your sub-classes and suppose all your constructors have extra code as well in addition to the initializer block code which would be added to them on the top during compilation. Now in such a situation, if you need to set only those fields which are set in the initializer block then you can't do that directly in your subclass as the most you can do here is to call a super class constructor (that too would normally re-set all the instance fields) ... right? Having a final instance method would solve your problem here. Choosing a suitable access specifier will again follow the same rules what has been discussed in article mentioned in above paragraph. In this case since the sub-classes require access to that method, so choosing 'protected' as the access specifier should be fine.


Liked the article? Subscribe to this blog for regular updates. Wanna follow it to tell the world that you enjoy GeekExplains? Please find the 'Followers' widget in the rightmost sidebar.



Share/Save/Bookmark


2 comments:

Ranvijay Singh said...

Hi geek,
During my project development .I need to do some work related to enrolment generation
As this is easy but very common. I have done this at back end and I would like to share it to all visitors if you find it some thing which make an article then please publish it.

Generating Enrolment Number by Using Trigger and Procedure
There was a requirement of generating enrolment number for students in my project
After some initial analysis I thought it will be better to do all these stuff by using
Trigger and procedure .so this require no change at front end and there
Are no other components getting affected by this new functionality?

How I implement it
In my case it is required to generate enrolment number when ever student is activated. And when ever student is activated the activation_date column. Get updated by current date. So I used this event to generate enrolment number
For this I used a trigger and from within that trigger called a procedure this procedure takes a parameter student id .generate a unique enrolment number for this student id
And store this newly generated enrolment number into another table named as enrolment with student id

Procedure Used:

DELIMITER //

CREATE PROCEDURE generate_enrolment(stud_id varchar(20))

BEGIN
DECLARE cur_date date;
DECLARE curr_year varchar(4);
DECLARE curr_month varchar(4);
DECLARE curr_year_month varchar(10);
DECLARE enrol int(6);

SET cur_date = CURRENT_DATE();
SET curr_year = SUBSTR((CONVERT(year(cur_date),char(4))) FROM 3);
SET curr_month =CONVERT((month(cur_date)),char(2));

IF LENGTH(curr_month) = 1 THEN
SET curr_month = concat('0',curr_month);
END IF;

SELECT max(auto_id) INTO enrol FROM academy_iteducation.enrolment;

IF ISNULL(enrol) = 1 THEN
SET enrol = 100100;
ELSE
set enrol=enrol+1;
END IF;

set curr_year_month=concat(curr_year,curr_month,cast(enrol as char));
INSERT INTO academy_iteducation.enrolment VALUES(curr_year_month,stud_id,enrol);
END //


How This Procedure Generate Enrolment Number:

1. Get System current date
2. Retrieving last two digits of current year and find current month if length of current month is one then concatenate zero before the current month
3. Fire select query which retrieve max from auto_id column of enrolment table
This column is supporting to generate enrolment number .as first time this procedure is called. This query returns null in that case we assign a number to a variable (enrol) in all other cases else part will be execute .So this variable is incremented by one and this makes enrolment number unique. After it all are straight forward just concatenate enrolment number and insert it into enrolment table

Trigger Used:

DELIMITER //

CREATE TRIGGER enrol_trigger AFTER UPDATE ON academy_iteducation.stud_details

FOR EACH ROW begin
declare enrol_id varchar(20);

IF new.activation_date != old.activation_date or isnull(old.activation_date)=1 THEN

select stud_id into enrol_id from academy_iteducation.stud_details where stud_id=old.stud_id;

CALL academy_iteducation.generate_enrolment(enrol_id);

END IF;
end //

Enrolment table (having enrolment numbers):




Any suggestions regarding this will be greatly acceptable. Any one can contact me at ranvijayps@gmail.com.

Geek said...

Thanks Ranvijay. The trigger/stored-proc combo does make an article material. Will try to publish it at the earliest possible. Keep visiting/posting!