Java constructor basics: objects and fields with no current value - java

I have a couple of questions about constructors in Java:
How are you supposed to initialise/create objects that the class relies on? For example, I have a DateTime object in my 'time' class. Should I have a private DateTime _date; field as part of the class and then stick _date = new DateTime(); in the constructor? Or is it better to initialise this object in a relevant method?
What do you do if fields are supposed to be uninitialised when a new object of their class is created (i.e. their values are set later when methods of the class are invoked on the object)? In the constructor, do I initialise them to null or some nonsense value?
Thanks for your help.

Fundamentally, the answer to both questions is: It's up to you.
If you do private DateTime _date = new DateTime();, that will happen as part of instance construction as though it were in the constructor (it will happen immediately before the step-by-step code in the constructor is run). I can't find that said baldly in the JLS (that doesn't mean it's not there), but it'll be somewhere in Section 8 and/or Section 15. So whether it's at the declaration or in the constructor is your call. It has the advantage that if you have multiple constructors, it will happen regardless of which one is called; it has the disadvantage of having the construction code in more than one place.
They are implicitly initialized to null, 0, false, etc. (their "default value"), depending on what type they are, as part of the definition of the Java language. So you can explicitly initialize them to null and such if you want for clarity, emphasis, readability, whatever, but it's not required.

In answer to your second question, you can explicitly set the fields that are objects to null within the constructor. However, this is not needed because if you do not construct or create the object, it would automatically be set to null. For example,
Public class MyClass {
private User user;
public MyClass(){
this.user;
}
}
The constructor above is same as:
public MyClass(){
this.user = null;
}

It's the primary responsibility of the constructor to ensure that the instance is set up obeying the class invariants (unless it throws an exception). The invariants are probably going to be simpler if the fields are required to be nonnull. In general you want to avoid using null. NPEs are really common, and shouldn't be.
(Also I strongly advise sticking with standard Java conventions.)

To be honest: I handle it differently all the times. Sometimes I set the variable on declaration (like T.J. Crowder), sometimes in the constructor and seldom there is a initDefaults() method which is called by the constructor, pl
I recommend never to initialize fields to nonsense values. When reading the field you just can't be sure if it is nonsense or intentionally that value. You should define for your whole system what a null value means or (if you can't avoid it) a special 'default' value, and how methods return values, e.g. Robert Martin recommends to rather return an empty array than null for an empty list (that way you avoid NPEs).
Good Luck :-)

Related

Can I use setter method for a replacement of final variable In the following way

Most of us understand the consequences of shared mutability, and it is said that always prefer immutability(final modifier, set once and you can't change it) if you have a chance. I have seen few coding examples where People are actually making fields final or setters as private or even removing setters for a class (which can be DTO, Model or Entity class) and another class (a builder class which can set values once to that immutable class) is used to create and set fields of the Immutable class To ensure no other class is able to modify the state. Which seems a burden to me. SO I have come-up with this thought (below I am giving an example)
public class TestDataClass {
private String name;
public String getName() {
return name;
}
public void setName(Supplier<String> supplier) throws Exception {
if(Objects.isNull(name))
{this.name = supplier.get();return;}
throw new Exception("This field is immutable and already has a value "+this.name);
}
}
In this way either you can set values through setter like this objectOfTestDataClass.setName(() -> {return Perform_Desired_Logic;});
or
objectOfTestDataClass.setName(() ->"My Name"); if it is plain setter. Then also you dont have to create a bulder class or make setters private or omit setter method
In this way, I can get rid of variable initialization during Instantiation also once you set fields to become Immutable(I am not considering reflection).
I want your expert opinion to validate how legitimate is my thought, Can I consider this as Immutability? Am I missing something? in that case please correct me.
There are several things to note
Using a Supplier<String> instead of a String does not improve the code. There are only two cases, the intended case where the method is only executed once and the code of the supplier gets executed immediately and the erroneous case, where the supplier does not get executed, but where’s the sense in optimizing the erroneous case?
If a particular property supports being null, that approach fails to handle the case when it should be fixed to `null.
The API signature does not indicate that the class should be treated like immutable. Most readers will assume that it is mutable. So they may try to modify the object and not even notice the error if you’re going to remove the exception throwing statement, as said in a comment.
Immutable objects created by a builder are definitely completed and truly immutable once build. In contrast, your class allows the creator to forget setting some properties to fixed values, producing an actually mutable object.
Since instances of this class are not guaranteed to be immutable, they also do not have the guaranty to be thread safe that is usually associated with immutable objects.
What you wrote allows to not set more than one time a field of an object.
But it is not a way to create object with a fully initialized state as a constructor or a builder can provide.
So, if the client manipulates the object with a not complete or corrupted state, it could not work as expected.
Besides, providing setters that may be invoked by the clients at compile time but which the misuses would be known only at runtime (by throwing an exception) is not a friendly and good designed API.
Example of issue with an object that has a not complete state.
Take a Rectangle class.
It is composed of 4 mandatory information (height, weight, x and y coordinates).
These are represented by 4 instance fields :
int x, int y, int width, int height
Suppose the class provides an instance method boolean contains(Point p) to determinate if a Point (x, y coordinates) is included in it.
If you apply your method to value fields of this class, you may create Rectangle instances with incomplete/partial state.
The contains() method could not work. It should perform different checks and if a field is missing in Rectangle, it should may be even throw an exception.
Example of issue with an object which the state may be corrupted
If your object may be manipulated by multiple threads, using your way to value the fields of the object may set the object in an unexpected and inconsistent state.
Two threads may manipulate the object at the same time and changing two fields that should not be changed in this way.
To avoid it, you are forced to use explicit synchronization mechanisms for both reading and writing of fields.
Ii you use a constructor or a builder, you have not these problems as you get out of the box a complete, unmodifiable (de facto thread-safe) object with a clear API.

No arg constructor or arg constructor

In my program I read a fixed length file, stored each string in a local variable, and then stored every value into a class type array list. For creating the object of an array list, I used argument constructor with all the variables. The below code demonstrates this.
String a = "text1";
String b = "text2";
SampleModel sm = new SampleModel(a,b);
ArrayList<SampleModel> sampleList = new ArrayList<>();
sampleList.add(sm);
I find this absolutely right but my colleague asked me to change it to a no arg constructor and call getters and setters instead. That would be like below.
SampleModel sm = new SampleModel();
ArrayList<SampleModel> sampleList = new ArrayList<>();
String a = "text1";
String b = "text2";
sm.setA(a);
sm.setB(b);
sampleList.add(sm);
Is there any reason to prefer a no arg constructor over argument constructor? (My program has around 15 variables)
It depends on how the class will be used.
For example, an immutable class will need a constructor that takes arguments, and no setters.
But a Java Bean will need a no-argument constructor, and setters.
Some things to consider:
Encapsulation can be valuable. Other than special cases like JavaBeans, usually the interface of the class can be designed based on the desired interactions, not on the current set of data members.
Methods have names. Java does not support named arguments. Method names communicate how an actual parameter is being used, in the calling code. If your class has more than a handful of parameters, passing them via methods can result in more readable calling code.
Immutable classes have value. If you're adding named setters directly in your class, it won't be immutable. The builder pattern allows you to accept construction parameters even for immutable classes.
Whether I use accessors and mutators for a class variable depends on two things:
Whether the variable is essential or optional to the object.
Whether it might ever change in the course of using the object, or whether it is final.
Variables that are necessary and final should be in the constructor, in my opinion, and should not have mutators. Variables that are optional should have accessors and mutators. Variables that are essential but might change are up to your discretion. I would probably put them in the constructor, but use a Builder design pattern to avoid having a long list of arguments for the constructor.
A constructor that takes arguments is essentially for convenience (although that's not always the case if the object requires arguments in order to be constructed properly, it is here without seeing anymore context); it's doing the exact same thing as the set methods are doing.
There is no reason to not have a constructor take arguments, as long as those arguments "make sense" in the context of the object. In other words, it's more of a semantics thing to consider than a correctness thing.
If the constructor is:
public SampleModel(String a, String b)
{
this.a = a;
this.b = b;
}
It probably doesn't make a difference.
It might just be that it's easier to see whats going on than having a large comma separated list. This might also be a nice place to use Double Brace Initialization:
String a = "text1";
String b = "text2";
SampleModel sm = new SampleModel() {{
setA(a);
setB(b);
}};
ArrayList<SampleModel> sampleList = new ArrayList<>() {{
add(sm);
}};
Quotation from Fowler and Beck book: "Refactoring"
Long Parameter List
In our early programming days we were taught to pass in as parameters everything needed by a routine. This was understandable because the alternative was global data, and global data is evil and usually painful. Objects change this situation because if you don't have something you need, you can always ask another object to get it for you. Thus with objects you don't pass in everything the method needs; instead you pass enough so that the method can get to everything it needs. A lot of what a method needs is available on the method's host class. In object-oriented programs parameter lists tend to be much smaller than in traditional programs. This is good because long parameter lists are hard to understand, because they become inconsistent and difficult to use, and because you are forever changing them as you need more data. Most changes are removed by passing objects because you are much more likely to need to make only a couple of requests to get at a new piece of data. Use Replace Parameter with Method when you can get the data in one parameter by making a request of an object you already know about. This object might be a field or it might be another parameter. Use Preserve Whole Object to take a bunch of data gleaned from an object and replace it with the object itself. If you have several data items with no logical object, use Introduce Parameter Object. There is one important exception to making these changes. This is when you explicitly do not want to create a dependency from the called object to the larger object. In those cases unpacking data and sending it along as parameters is reasonable, but pay attention to the pain involved. If the parameter list is too long or changes too often, you need to rethink your dependency structure.

Why are no-arg constructors subject to being instantiated in an invalid state?

I was looking to JavaBean advtanges and disadvantages. In the disadvantages section, I came across this:
A class with a nullary constructor is subject to being instantiated in an invalid state.
Wikipedia - JavaBeans
What exactly does this mean? How does this opppse to constructors that have parameter arguments?
If such a class is instantiated manually by a developer (rather than automatically by some kind of framework), the developer might not realize that the class has been improperly instantiated.
A JavaBean framework may perform automatic operations on an instantiated JavaBean, for example, by calling methods, passing parameters to regular methods, etc. depending on what the JavaBean is designed to do, and how the framework is expected to process JavaBeans under its control.
The compiler can’t detect such a problem, and even if it’s documented, there’s no guarantee that the developer will see the documentation.
Rephrased: "Developers aren't always diligent, and even when they are, they're not always right."
Components designed explicitly for consumption by automated tools aren't always well designed for consumption by actual people.
Consider java.net.URL
Let's suppose it has a null constructor, and a setter for the actual url string, port, etc. When set up using the null constructor, it will be in an invalid state, and anyone trying to use that URL object will have a problem.
URL clearly doesn't have a null constructor. I used this just to highlight the point that for some objects, having a null constructor can initialize them in an invalid state
Consider a simple class that has a simple String attribute called name. It might have a public String getName() method to fetch the value of the attribute. Although the signature of that method says it returns a reference to a String object, the design of your class might be more restrictive than that. The design might state that the name may not be null, may not be empty, and must begin with an upper case character, and must be unique, for example. Any object of that class that was ever observed to have a name that did not conform to all those restrictions would be invalid.
The job of the constructor is to set up a new object in its initial state, which must be a valid state. Some of the kinds of restrictions on values are impossible for a constructor to meet without the constructor being given addition information about how to construct the object.
A constructor without arguments can not be given that information, so there are some kinds of restriction the design of a Java Bean can not apply, or can apply only if the constructor is exempt from them. Being exempt from them really means allowing the constructor to create invalid objects.
An object created by a nullary constructor will not set value to any of its properties. If a framework sets it, it will likely know which properties need to be set to what kind of values before the object can be used. However, a programmer, who is not familiar with the intention of the object, might not know or forget to set the properties to valid values. Even if there is documentation to stipulate what values need to be set for which parameters, a human programmer may not read that documentation or remember to follow all the rules.
For example, in the following code, if the object "data" is not set to a valid Enum type (such as null), an InvalidObjectException will be raised.
Object toJavaTypeData(Object data)
throws OpenDataException, InvalidObjectException {
try {
return Enum.valueOf(enumClass, (String) data);
} catch (IllegalArgumentException e) {
// missing enum constants
final InvalidObjectException ioe =
new InvalidObjectException("Enum constant named " +
(String) data + " is missing");
ioe.initCause(e);
throw ioe;
}
}

Instantiate objects in initialization?

I have a class that holds another objects inside it (List, Set and objects from my application).
public class SomeClass {
private List l;
private SomeObject obj;
//...
}
Is a good practice instantiate these objects where the SomeClass object is created to avoid NullPointerException? Something like:
public class SomeClass{
private List l = new ArrayList();
private SomeObject obj = new SomeObject();
//...
}
In a normal way, these objects will be generated in some processing/analysis, but errors can occur and the objects still with null value.
Yes, it is a good practice to do so. The constructor is a natural place to instantiate member objects. You can also create them right where they are declared:
private List l = new ArrayList();
However, it might be a good idea to restructure or modify your code so that NullPointerExceptions won't occur, regardless of the order in which the methods are called.
If an empty List or a default object of that class is a valid state in every following operation, yes, instantiate a default. However, if the default would be an invalid state, don't do it.
Well I prefer to initialize because sometimes is a headache to find where's the null pointer exception, and if u initialize your objects with constructors the object inside should be initialized.
Hope this help you.
It's generally good practice to instantiate member fields (whether objects or primitives) at creation time whenever the default value (0, false, or null) is not what you want. One time to defer this is for lazy instantiation. (This is used, for instance, when an object might not be needed after all and creating it is expensive.) Another time to defer this is when other initialization needs to take place beforehand.
Assuming you want to initialize a field at object creation time, there are two ways to do it: with an initializer expression as you showed or in the constructor(s). There isn't too much difference, other than that instance initializers run before the first line of the constructor. This may or may not cause problems, depending on your code logic.
It's also a good idea to declare member fields final whenever they are initialized at object creation and are expected to not change during the life of the object. A side benefit of declaring a field final is that the compiler will catch any failure to initialize it. (The compiler requires definite assignment to consider a final field to be properly initialized.)
You are talking about eager construction versus lazy construction. There are places where each has value.
In many situations, it is better to lazily create things as it saves memory. But then you must check for null every time you try to get data
In some situations, it makes sense to create the object upfront, either to avoid the null checking mentioned above or to avoid the object creation time hit during an intensive process
It is normal to generate them like this, but it's not a nice way to code to generate them just to avoid NPE. There should be proper validation in code, rather than assigning garbage-eligible objects which won't be utilized.
You can also assign some default states - like Collections.emptyList(), or
in a constants class:
DEFAULT_STATE = new SomeState();
then simply
class A {
State obj = Constants.DEFAULT_STATE;
}

Uninitialized variables and members in Java

Consider this:
public class TestClass {
private String a;
private String b;
public TestClass()
{
a = "initialized";
}
public void doSomething()
{
String c;
a.notify(); // This is fine
b.notify(); // This is fine - but will end in an exception
c.notify(); // "Local variable c may not have been initialised"
}
}
I don't get it. "b" is never initialized but will give the same run-time error as "c", which is a compile-time error. Why the difference between local variables and members?
Edit: making the members private was my initial intention, and the question still stands...
The language defines it this way.
Instance variables of object type default to being initialized to null.
Local variables of object type are not initialized by default and it's a compile time error to access an undefined variable.
See section 4.12.5 for SE7 (same section still as of SE14)
http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.5
Here's the deal. When you call
TestClass tc = new TestClass();
the new command performs four important tasks:
Allocates memory on the heap for the new object.
Initiates the class fields to their default values (numerics to 0, boolean to false, objects to null).
Calls the constructor (which may re-initiate the fields, or may not).
Returns a reference to the new object.
So your fields 'a' and 'b' are both initiated to null, and 'a' is re-initiated in the constructor. This process is not relevant for method calling, so local variable 'c' is never initialized.
For the gravely insomniac, read this.
The rules for definite assignment are quite difficult (read chapter 16 of JLS 3rd Ed). It's not practical to enforce definite assignment on fields. As it stands, it's even possible to observe final fields before they are initialised.
The compiler can figure out that c will never be set. The b variable could be set by someone else after the constructor is called, but before doSomething(). Make b private and the compiler may be able to help.
The compiler can tell from the code for doSomething() that c is declared there and never initialized. Because it is local, there is no possibility that it is initialized elsewhere.
It can't tell when or where you are going to call doSomething(). b is a public member. It is entirely possible that you would initialize it in other code before calling the method.
Member-variables are initialized to null or to their default primitive values, if they are primitives.
Local variables are UNDEFINED and are not initialized and you are responsible for setting the initial value. The compiler prevents you from using them.
Therefore, b is initialized when the class TestClass is instantiated while c is undefined.
Note: null is different from undefined.
You've actually identified one of the bigger holes in Java's system of generally attempting to find errors at edit/compile time rather than run time because--as the accepted answer said--it's difficult to tell if b is initialized or not.
There are a few patterns to work around this flaw. First is "Final by default". If your members were final, you would have to fill them in with the constructor--and it would use path-analysis to ensure that every possible path fills in the finals (You could still assign it "Null" which would defeat the purpose but at least you would be forced to recognize that you were doing it intentionally).
A second approach is strict null checking. You can turn it on in eclipse settings either by project or in default properties. I believe it would force you to null-check your b.notify() before you call it. This can quickly get out of hand so it tends to go with a set of annotations to make things simpler:
The annotations might have different names but in concept once you turn on strict null checking and the annotations the types of variables are "nullable" and "NotNull". If you try to place a Nullable into a not-null variable you must check it for null first. Parameters and return types are also annotated so you don't have to check for null every single time you assign to a not-null variable.
There is also a "NotNullByDefault" package level annotation that will make the editor assume that no variable can ever have a null value unless you tag it Nullable.
These annotations mostly apply at the editor level--You can turn them on within eclipse and probably other editors--which is why they aren't necessarily standardized. (At least last time I check, Java 8 might have some annotations I haven't found yet)

Categories