Use cases of instance initializer - java

I know instance initializers will be called before my constructor, and they are like static constructors, only that they are called everytime I create an instance of the class. E.g.
public class App {
public static void main( String[] args ){
new App();
new App();
}
static{
System.out.println( "static initializer" );
}
public App(){
System.out.println( "constructor" );
}
{
System.out.println( "instance initializer" );
}
}
Outputs:
static initializer
instance initializer
constructor
instance initializer
constructor
But why should I ever use them? I just could write the logic in my constructor, and if I want to do the logic before some already existing constructor I could just add it to the beginning of the constructor.
I also see no advantage on inherited classes, because even if I overwrite the constructor I can still just implement own logic and call the parents constructor afterwards.
What is a proper use case for instance initializers in Java, or any language at all? Or is it always possible to get the same functionallity with constructors?

From the JLS 8.6 - Instance Initializers:
An instance initializer declared in a class is executed when an instance of the class is created.
From the JLS 8.8 - Constructor Declarations:
A constructor is used in the creation of an object that is an instance of a class.
Thus confirming your point that everything that gets done in instance initializers can also be done in your constructor.
This leaves proximity. Compare:
Map<String, String> lookup = new HashMap<>();
{
lookup.put("Hello", "Hello");
}
with:
Map<String, String> lookup = new HashMap<>();
// Maybe some considerable number of lines of code.
public Test() {
lookup.put("Hello", "Hello");
}
There is clearly no functional difference between these two but putting the two closer together makes sense.
Of course there is the edge case of:
public Test() throws Exception {
// ...
}
which you cannot do in an instance initialiser.

If you have multiple constructors, instance initializers will also be executed.
That way you don't have to copy-paste code.

I used it couple of times when i make a customized anonymous class instances where you can't explicitly declare a constructor.
see here
For example,
public static final Set<String> someStringSet = new HashSet<String>(){
{
add("string1");
add("string2");
add("string3");
}
};
It can be an anonymous hashmap or anything you can think of that needs to be modified
at the beginning.

Related

When to use an object to call a method?

I am confused on when to use an object to call a method. For instance, sometimes I have to do object.someMethod() and other times the method works when it is just called someMethod(). If anyone could clarify when I need to use an object and when I do not, that would be great!
When you are calling non-static class members, you always need to specify the instance. However, there is one short-cut if you are inside a member function: Instead of writing this.otherMethod(), you can omit the this. part and only write otherMethod(), as it will be implicitly assumed by the compiler. It is a common situation and readability is not hurt from omitting it:
class Foo {
public void someMethod() {
otherMethod(); // same as calling: this.otherMethod()
}
public void otherMethod() {
}
}
MyClass object = new MyClass();
object.someMethod();
MyClass object2 = new MyClass();
someMethod(); // ERROR: from the context, it is not clear which instance is meant:
// Do you mean object.someMethod() or object2.someMethod()?
Note that it only works for methods of the same class. If you call it from outside, it will be a compile error. In the example above, it is mandatory that you explicitly write object.someMethod() or object2.someMethod().

Why can method reference use non-final variables?

I had some confusion about inner classes and lambda expression, and I tried to ask a question about that, but then another doubt arose, and It's probable better posting another question than commenting the previous one.
Straight to the point: I know (thank you Jon) that something like this won't compile
public class Main {
public static void main(String[] args) {
One one = new One();
F f = new F(){ //1
public void foo(){one.bar();} //compilation error
};
one = new One();
}
}
class One { void bar() {} }
interface F { void foo(); }
due to how Java manages closures, because one is not [effectively] final and so on.
But then, how come is this allowed?
public class Main {
public static void main(String[] args) {
One one = new One();
F f = one::bar; //2
one = new One();
}
}
class One { void bar() {} }
interface F { void foo(); }
Is not //2 equivalent to //1? Am I not, in the second case, facing the risks of "working with an out-of-date variable"?
I mean, in the latter case, after one = new One(); is executed f still have an out of date copy of one (i.e. references the old object). Isn't this the kind of ambiguity we're trying to avoid?
A method reference is not a lambda expression, although they can be used in the same way. I think that is what is causing the confusion. Below is a simplification of how Java works, it is not how it really works, but it is close enough.
Say we have a lambda expression:
Runnable f = () -> one.bar();
This is the equivalent of an anonymous class that implements Runnable:
Runnable f = new Runnable() {
public void run() {
one.bar();
}
}
Here the same rules apply as for an anonymous class (or method local class). This means that one needs to effectively final for it to work.
On the other hand the method handle:
Runnable f = one::bar;
Is more like:
Runnable f = new MethodHandle(one, one.getClass().getMethod("bar"));
With MethodHandle being:
public class MethodHandle implements Runnable {
private final Object object;
private final Method method;
public MethodHandle(Object object, java.lang.reflect.Method method) {
this.object = Object;
this.method = method;
}
#Override
public void run() {
method.invoke(object);
}
}
In this case, the object assigned to one is assigned as part of the method handle created, so one itself doesn't need to be effectively final for this to work.
Your second example is simply not a lambda expression. It's a method reference. In this particular case, it chooses a method from a particular object, which is currently referenced by the variable one. But the reference is to the object, not to the variable one.
This is the same as the classical Java case:
One one = new One();
One two = one;
one = new One();
two.bar();
So what if one changed? two references the object that one used to be, and can access its method.
Your first example, on the other hand, is an anonymous class, which is a classical Java structure that can refer to local variables around it. The code refers to the actual variable one, not the object to which it refers. This is restricted for the reasons that Jon mentioned in the answer you referred to. Note that the change in Java 8 is merely that the variable has to be effectively final. That is, it still can't be changed after initialization. The compiler simply became sophisticated enough to determine which cases will not be confusing even when the final modifier is not explicitly used.
The consensus appears to be that this is because when you do it using an anonymous class, one refers to a variable, whereas when you do it using a method reference, the value of one is captured when the method handle is created. In fact, I think that in both cases one is a value rather than a variable. Let's consider anonymous classes, lambda expressions and method references in a bit more detail.
Anonymous classes
Consider the following example:
static Supplier<String> getStringSupplier() {
final Object o = new Object();
return new Supplier<String>() {
#Override
public String get() {
return o.toString();
}
};
}
public static void main(String[] args) {
Supplier<String> supplier = getStringSupplier();
System.out.println(supplier.get()); // Use o after the getStringSupplier method returned.
}
In this example, we are calling toString on o after the method getStringSupplier has returned, so when it appears in the get method, o cannot refer to a local variable of the getStringSupplier method. In fact it is essentially equivalent to this:
static Supplier<String> getStringSupplier() {
final Object o = new Object();
return new StringSupplier(o);
}
private static class StringSupplier implements Supplier<String> {
private final Object o;
StringSupplier(Object o) {
this.o = o;
}
#Override
public String get() {
return o.toString();
}
}
Anonymous classes make it look as if you are using local variables, when in fact the values of these variables are captured.
In contrast to this, if a method of an anonymous class references the fields of the enclosing instance, the values of these fields are not captured, and the instance of the anonymous class does not hold references to them; instead the anonymous class holds a reference to the enclosing instance and can access its fields (either directly or via synthetic accessors, depending on the visibility). One advantage is that an extra reference to just one object, rather than several, is required.
Lambda expressions
Lambda expressions also close over values, not variables. The reason given by Brian Goetz here is that
idioms like this:
int sum = 0;
list.forEach(e -> { sum += e.size(); }); // ERROR
are fundamentally serial; it is quite difficult to write lambda bodies
like this that do not have race conditions. Unless we are willing to
enforce -- preferably at compile time -- that such a function cannot
escape its capturing thread, this feature may well cause more trouble
than it solves.
Method references
The fact that method references capture the value of the variable when the method handle is created is easy to check.
For example, the following code prints "a" twice:
String s = "a";
Supplier<String> supplier = s::toString;
System.out.println(supplier.get());
s = "b";
System.out.println(supplier.get());
Summary
So in summary, lambda expressions and method references close over values, not variables. Anonymous classes also close over values in the case of local variables. In the case of fields, the situation is more complicated, but the behaviour is essentially the same as capturing the values because the fields must be effectively final.
In view of this, the question is, why do the rules that apply to anonymous classes and lambda expressions not apply to method references, i.e. why are you allowed to write o::toString when o is not effectively final? I do not know the answer to that, but it does seem to me to be an inconsistency. I guess it's because you can't do as much harm with a method reference; examples like the one quoted above for lambda expressions do not apply.
No. In your first example you define the implementation of F inline and try to access the instance variable one.
In the second example you basically define your lambda expression to be the call of bar() on the object one.
Now this might be a bit confusing. The benefit of this notation is that you can define a method (most of the time it is a static method or in a static context) once and then reference the same method from various lambda expressions:
msg -> System.out::println(msg);

Why is it preferable to call a static method statically from within an instance of the method's class?

If I create an instance of a class in Java, why is it preferable to call a static method of that same class statically, rather than using this.method()?
I get a warning from Eclipse when I try to call static method staticMethod() from within the custom class's constructor via this.staticMethod().
public MyClass() { this.staticMethod(); }
vs
public MyClass() { MyClass.staticMethod(); }
Can anyone explain why this is a bad thing to do? It seems to me like the compiler should already have allocated an instance of the object, so statically allocating memory would be unneeded overhead.
EDIT:
The gist of what I'm hearing is that this is bad practice mainly because of readability, and understandably so. What I was really trying to ask (albeit not very clearly) was what differences there are at 'compilation', if any, between calling MyClass.staticMethod() or this.staticMethod().
Static methods are not tied to an instance of the class, so it makes less sense to call it from a this than to call it from Class.staticMethod(), much more readable too.
MyClass.staticMethod() makes it clear that you are calling a static (non-overrideable) method.
this.staticMethod() misleads the reader into thinking that it is an instance method.
staticMethod() is also on the misleading side (though I normally do it that way).
If you think of people reading your code as unfamiliar with it you tend to try to make the code clearer, and this is a case where the code is clearer by having ClassName.method instead of instance.method.
In addition to the other answers which have mentioned making it clear you're using a static method, also note that static methods are not polymorphic, so being explicit with the class name can remove any confusion as to which method is going to be called.
In the code below, it's not entirely obvious that b.test() is going to return "A" if you're expecting the polymorphism of a non-static method:
public class TestStaticOverride
{
public static void main( String[] args )
{
A b = new B();
System.out.println( "Calling b.test(): " + b.test() );
}
private static class A
{
public static String test() { return "A"; }
}
private static class B extends A
{
public static String test() { return "B"; }
}
}
If you change the code to B b = new B(); it will print out "B".
(Whether it's ever a good idea to "override" static methods is probably a discussion for another day...)
Static methods are really not part of your instance - and it will not be able to access any of your instance variables anyway, so I would dare thinking it doesn't make a lot of sense calling it from the constructor.
If your need to initialize static objects use
private static List l = new ArrayList(); static { l.add("something"); }
If you still need to call it its perfectly legal to call local static methods without prefixing your local class name, like this (no eclipse warning)
public MyClass() { staticMethod(); }
Because this. normally reference to instance methods, therefore, it's a bad idea to do that.

How is an instance initializer different from a constructor?

In other words, why would you need an instance initializer? What difference or advantage do you have in writing a instance initializer over a constructor?
This seems to explain it well:
Instance initializers are a useful alternative to instance variable
initializers whenever:
initializer code must catch exceptions, or
perform fancy calculations that can't be expressed with an instance variable initializer. You could, of course, always write such code in
constructors.
But in a class that had multiple constructors, you would have to repeat the code in each constructor. With an instance initializer, you
can just write the code once, and it will be executed no matter what
constructor is used to create the object. Instance initializers are
also useful in anonymous inner classes, which can't declare any
constructors at all.
From: JavaWorld Object initialization in Java.
In terms of object lifecycle, there is no difference. Both are invoked at construction time, and logically the initializer block can be considered part of construction.
Semantically, an initializer is a nice tool to have for several reasons:
the initializer can improve code readability by keeping the initialization logic next to the variable being initialized:
public class Universe {
public int theAnswer;
{
int SIX = 6;
int NINE = 7;
theAnswer = SIX * NINE;
}
// a bunch of other vars
}
vs
public class Universe {
public int theAnswer;
// a bunch of other vars
public Universe() {
int SIX = 6;
int NINE = 7;
theAnswer = SIX * NINE;
// other constructor logic
}
}
Initializers are invoked regardless
of which constructor is used.
Initializers can be used in anonymous
inner classes, where constructors
can't.
When you have many constructors and want some common code to be executed for each constructor you can use instance initializer.As it is called for all constructors.
I would avoid the instance initializer idiom in general - the only real advantage it gives over variable initializers is exception handling.
And since an init method (callable from constructor) can also do exception handling and also centralizes constructor setup code, but has the advantage that it can operate on constructor parameter values, I'd say that the instance initializer is redundant, and therefore to be avoided.
The real advantage of instance initializers over constructors is seen when we use an anonymous inner class.
Anonymous inner classes can't have a constructor (as they're anonymous), so they're a pretty natural fit for instance initializers.
At the time of object creation, if we want to perform initialise of instance variables, then we should go for Constructor, other than initialisation activity if we want to perform any activity at the time of object creation then we should go for instance block.
We can't replace constructor with instance block because constructor can take argument but instance block can't take arguments.
We can't replace instance block wih constructor because a class can contain more than one constructor. If we want to replace instance block with constructor then in every constructor we have to write instance block code because at runtime which constructor will be called we can't expect, this will unnecesarily increase duplicate code.
Example :
class MyClass{
static int object_count = 0;
MyClass(){
object_count++;
}
MyClass(int i){
object_count++;
}
void getCount() {
System.out.println(object_count);
}
public static void main(String... args) {
MyClass one = new MyClass();
MyClass two = new MyClass(2);
two.getCount();
}
}
Output : 2
class MyClass{
static int object_count = 0;
{
object_count++;
}
MyClass(){
}
MyClass(int i){
}
void getCount() {
System.out.println(object_count);
}
public static void main(String... args) {
MyClass one = new MyClass();
MyClass two = new MyClass(2);
two.getCount();
}
}
Output : 2
Initializer is way to share code between constructors and it make code more readable if initializer is used with variable declaration.
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.
Oracle documentation

Use of Initializers vs Constructors in Java

So I've been brushing up on my Java skills as of late and have found a few bits of functionality that I didn't know about previously. Static and Instance Initializers are two such techniques.
My question is when would one use an initializer instead of including the code in a constructor? I've thought of a couple obvious possibilities:
static/instance initializers can be used to set the value of "final" static/instance variables whereas a constructor cannot
static initializers can be used to set the value of any static variables in a class, which should be more efficient than having an "if (someStaticVar == null) // do stuff" block of code at the start of each constructor
Both of these cases assume that the code required to set these variables is more complex than simply "var = value", as otherwise there wouldn't seem to be any reason to use an initializer instead of simply setting the value when declaring the variable.
However, while these aren't trivial gains (especially the ability to set a final variable), it does seem that there are a rather limited number of situations in which an initializer should be used.
One can certainly use an initializer for a lot of what is done in a constructor, but I don't really see the reason to do so. Even if all constructors for a class share a large amount of code, the use of a private initialize() function seems to make more sense to me than using an initializer because it doesn't lock you into having that code run when writing a new constructor.
Am I missing something? Are there a number of other situations in which an initializer should be used? Or is it really just a rather limited tool to be used in very specific situations?
Static initializers are useful as cletus mentioned and I use them in the same manner. If you have a static variable that is to be initialized when the class is loaded, then a static initializer is the way to go, especially as it allows you to do a complex initialization and still have the static variable be final. This is a big win.
I find "if (someStaticVar == null) // do stuff" to be messy and error prone. If it is initialized statically and declared final, then you avoid the possibility of it being null.
However, I'm confused when you say:
static/instance initializers can be used to set the value of "final"
static/instance variables whereas a constructor cannot
I assume you are saying both:
static initializers can be used to set the value of "final" static variables whereas a constructor cannot
instance initializers can be used to set the value of "final" instance variables whereas a constructor cannot
and you are correct on the first point, wrong on the second. You can, for example, do this:
class MyClass {
private final int counter;
public MyClass(final int counter) {
this.counter = counter;
}
}
Also, when a lot of code is shared between constructors, one of the best ways to handle this is to chain constructors, providing the default values. This makes is pretty clear what is being done:
class MyClass {
private final int counter;
public MyClass() {
this(0);
}
public MyClass(final int counter) {
this.counter = counter;
}
}
Anonymous inner classes can't have a constructor (as they're anonymous), so they're a pretty natural fit for instance initializers.
I most often use static initializer blocks for setting up final static data, especially collections. For example:
public class Deck {
private final static List<String> SUITS;
static {
List<String> list = new ArrayList<String>();
list.add("Clubs");
list.add("Spades");
list.add("Hearts");
list.add("Diamonds");
SUITS = Collections.unmodifiableList(list);
}
...
}
Now this example can be done with a single line of code:
private final static List<String> SUITS =
Collections.unmodifiableList(
Arrays.asList("Clubs", "Spades", "Hearts", "Diamonds")
);
but the static version can be far neater, particularly when the items are non-trivial to initialize.
A naive implementation may also not create an unmodifiable list, which is a potential mistake. The above creates an immutable data structure that you can happily return from public methods and so on.
Just to add to some already excellent points here. The static initializer is thread safe. It is executed when the class is loaded, and thus makes for simpler static data initialization than using a constructor, in which you would need a synchronized block to check if the static data is initialized and then actually initialize it.
public class MyClass {
static private Properties propTable;
static
{
try
{
propTable.load(new FileInputStream("/data/user.prop"));
}
catch (Exception e)
{
propTable.put("user", System.getProperty("user"));
propTable.put("password", System.getProperty("password"));
}
}
versus
public class MyClass
{
public MyClass()
{
synchronized (MyClass.class)
{
if (propTable == null)
{
try
{
propTable.load(new FileInputStream("/data/user.prop"));
}
catch (Exception e)
{
propTable.put("user", System.getProperty("user"));
propTable.put("password", System.getProperty("password"));
}
}
}
}
Don't forget, you now have to synchronize at the class, not instance level. This incurs a cost for every instance constructed instead of a one time cost when the class is loaded. Plus, it's ugly ;-)
I read a whole article looking for an answer to the init order of initializers vs. their constructors. I didn't find it, so I wrote some code to check my understanding. I thought I would add this little demonstration as a comment. To test your understanding, see if you can predict the answer before reading it at the bottom.
/**
* Demonstrate order of initialization in Java.
* #author Daniel S. Wilkerson
*/
public class CtorOrder {
public static void main(String[] args) {
B a = new B();
}
}
class A {
A() {
System.out.println("A ctor");
}
}
class B extends A {
int x = initX();
int initX() {
System.out.println("B initX");
return 1;
}
B() {
super();
System.out.println("B ctor");
}
}
Output:
java CtorOrder
A ctor
B initX
B ctor
A static initializer is the equivalent of a constructor in the static context. You will certainly see that more often than an instance initializer. Sometimes you need to run code to set up the static environment.
In general, an instance initalizer is best for anonymous inner classes. Take a look at JMock's cookbook to see an innovative way to use it to make code more readable.
Sometimes, if you have some logic which is complicated to chain across constructors (say you are subclassing and you can't call this() because you need to call super()), you could avoid duplication by doing the common stuff in the instance initalizer. Instance initalizers are so rare, though, that they are a surprising syntax to many, so I avoid them and would rather make my class concrete and not anonymous if I need the constructor behavior.
JMock is an exception, because that is how the framework is intended to be used.
There is one important aspect that you have to consider in your choice:
Initializer blocks are members of the class/object, while constructors are not.
This is important when considering extension/subclassing:
Initializers are inherited by subclasses. (Though, can be shadowed)
This means it is basically guaranteed that subclasses are initialized as intended by the parent class.
Constructors are not inherited, though. (They only call super() [i.e. no parameters] implicitly or you have to make a specific super(...) call manually.)
This means it is possible that a implicit or exclicit super(...) call might not initialize the subclass as intended by the parent class.
Consider this example of an initializer block:
class ParentWithInitializer {
protected String aFieldToInitialize;
{
aFieldToInitialize = "init";
System.out.println("initializing in initializer block of: "
+ this.getClass().getSimpleName());
}
}
class ChildOfParentWithInitializer extends ParentWithInitializer{
public static void main(String... args){
System.out.println(new ChildOfParentWithInitializer().aFieldToInitialize);
}
}
output:
initializing in initializer block of: ChildOfParentWithInitializer
init
-> No matter what constructors the subclass implements, the field will be initialized.
Now consider this example with constructors:
class ParentWithConstructor {
protected String aFieldToInitialize;
// different constructors initialize the value differently:
ParentWithConstructor(){
//init a null object
aFieldToInitialize = null;
System.out.println("Constructor of "
+ this.getClass().getSimpleName() + " inits to null");
}
ParentWithConstructor(String... params) {
//init all fields to intended values
aFieldToInitialize = "intended init Value";
System.out.println("initializing in parameterized constructor of:"
+ this.getClass().getSimpleName());
}
}
class ChildOfParentWithConstructor extends ParentWithConstructor{
public static void main (String... args){
System.out.println(new ChildOfParentWithConstructor().aFieldToInitialize);
}
}
output:
Constructor of ChildOfParentWithConstructor inits to null
null
-> This will initialize the field to null by default, even though it might not be the result you wanted.
I would also like to add one point along with all the above fabulous answers . When we load a driver in JDBC using Class.forName("") the the Class loading happens and the static initializer of the Driver class gets fired and the code inside it registers Driver to Driver Manager. This is one of the significant use of static code block.
As you mentioned, it's not useful in a lot of cases and as with any less-used syntax, you probably want to avoid it just to stop the next person looking at your code from spending the 30 seconds to pull it out of the vaults.
On the other hand, it is the only way to do a few things (I think you pretty much covered those).
Static variables themselves should be somewhat avoided anyway--not always, but if you use a lot of them, or you use a lot in one class, you might find different approaches, your future self will thank you.
Note that one big issue with static initializers that perform some side effects, is that they cannot be mocked in unit tests.
I've seen libraries do that, and it's a big pain.
So it's best to keep those static initializers pure only.

Categories

Resources