I have a ClassA
object that sets method references inside of ClassB1
and ClassB2
objects. ClassB1
and ClassB2
objects will later use this method reference while running their methods. But, sometimes we do not set the method reference:
public class ClassA {
public ClassA() {
ClassB1 objB1 = new ClassB1();
ClassB2 objB2 = new ClassB2();
objB1.setFuncitonA(this::functionA);
objB2.setFuncitonA(this::functionA);
objB1.functionB();
objB2.functionB();
}
public void functionA(Integer x) {
x *= 2;
}
}
public class ClassB1 {
private Integer intObjB = new Integer(2);
private Consumer<Integer> functionA = null;
public void functionB() {
if(functionA != null) {
functionA.accept(intObjB);
}
}
public void setFuncitonA(Consumer<Integer> functionA) {
this.functionA = functionA;
}
}
public class ClassB2 {
private Integer intObjB = new Integer(2);
private Consumer<Integer> functionA = this::defaultFunctionA;
public void functionB() {
functionA.accept(intObjB);
}
public void setFuncitonA(Consumer<Integer> functionA) {
this.functionA = functionA;
}
public void defaultFunctionA(Integer intObj) {
return;
}
}
Should it be like in ClassB1
or like in ClassB2
, or, does it matter at all? What is the standard pattern of writing such code?
There is nomenclature for this sort of implementation decision: lazily instantiating your field, or eagerly instantiating your field.
ClassB1
lazily instantiates the functionA
consumer. This tells a maintainer (including yourself) that this consumer isn't always necessary for every new instance, and having it null
in certain contexts is safe. It does mean that you have to look over your shoulder when you're using it though, as in the case of the null
checks.
ClassB2
eagerly instantiates the functionA
consumer. This tells a maintainer (including yourself) that this consumer is required at instantiation time. This means you avoid the silly null
check if it's truly something you know at instantiation time (and in this case, it is something you either know or can get).
The standard pattern then becomes:
null
before use, then lazily instantiate the field.null
before use, then eagerly instantiate the field.There's no hard and fast rule to use or prefer one over the other. This will heavily depend on your use case.