Reputation: 3733
I see some people doing stuff like in the second constructor here:
public class Apples {
String color;
int quantity;
public Apples(String color, int quantity) {
this.color = color;
this.quantity = quantity;
}
public Apples(String color) {
this(color, 0);
}
}
What are the reasons for doing so? To me it seems like you're invoking an additional method(the constructor) just in order to save a few lines. I recall a professor a few years back saying it's bad practice, but I don't remember his reasons for saying so.
Upvotes: 4
Views: 367
Reputation: 663
According to DRY rule as @Peter Lawrey said is a good practice, but your code is definitely not the best practice. Why? Because overloading constructors isn't the best idea. Instead you could use static factory methods. Effective Java mentions that:
One advantage of static factory methods is that, unlike constructors, they have names.
So using static factory methods your code would look like this:
public class Apples {
String color;
int quantity;
private Apples(String color, int quantity) {
this.color = color;
this.quantity = quantity;
}
public static Apples newInstance(String color, int quantity) {
return new Apples(color, quantity);
}
public static Apples newEmptyInsatnce(String color) {
return new Apples(color, 0);
}
}
This way the method Apples.newEmptyInstance() is more informative about what it constructs than just an overloaded constructor. I was only assuming why your professor had told that was a bad idea.
Upvotes: 1
Reputation: 1941
It is possible to delegate call
to another
constructor
by using "this(params)" as the
first statement of current constructor.
We implement constructor call delegation if the initialization process is same for multiple constructors and they differ only int their inputs.
On constructor call delegation prg ctrl moves to another constructor, executes the code in it and then comes back to the next line that follows the delegation call.
class Myclass1
{
int a,b;
Myclass1()
{
this(10,20);//delegate to Myclass(int,int)
System.out.println("Myclass1() got job done from Myclass1(int, int)");
}
Myclass1(int q, int w)
{
//this();//err recursive constructor invocation
System.out.println("Myclass1(int,int)");
a = q;
b = w;
}
void f()
{
System.out.println("in f()");
f(10);//delegate call to f(10)
System.out.println("done f()");
}
void f(int x)
{
System.out.println("x is " + x);
}
void disp()
{
System.out.println(a + " " + b);
}
public static void main(String args[])
{
Myclass1 m1 = new Myclass1();
Myclass1 m2 = new Myclass1(1,2);
m1.disp();
m2.disp();
System.out.println("-------FN CALL DELEGATION---------------");
m1.f();
m1.f(99);
}
}
Upvotes: 1
Reputation: 16354
It can be considered as some API design practice, where you provide (excuse the term) but let's say generic constructor having as arguments all class instance variables as you mentioned:
public Apples(String color, int quantity) {
this.color = color;
this.quantity = quantity;
}
Then you implement some additional constructors which may take one or more of this instance variables, where you affect a default value
to non specified variables:
public Apples(String color) {
this(color, 0);
}
Here you are affecting a 0 to the quantity instance variable, which may also be written as below and which is fairly the same as above code (except that you are trying to reuse defined constructor):
public Apples(String color) {
this.color = color;
this.quantity = 0;
}
So that way you are thinking of some, user or colleague that lands down and want to use the snippet you wrote but does not know a lot about default values that classes may take when he is going to instantiate them (this is really showcased in more complex exapmles); but as good designer, you thought of him and provided diversity of constructors
that should ease his stuff.
BR.
Upvotes: 2
Reputation: 1661
I think that's not a bad idea if you think you implemented first constructor and then added 2nd one. Instead of writing all of those initializing code, by using existing ( and verified + used by other code well without problem ) init block, you can piggyback on it.
Code duplication might not so bad as you think, but that has human error possibility as well. You might copy&paste existing init block, but in case you tried manual typing then new code in the new constructor could be
this.color = color; [something else in the class] = quantity;
instead of
this.color = color; this.quantity = quantity;
by mistake, and I'm sure it will take your time to figure this out. You might think that won't be happening, but if you have class with 10+ parameters and want to add new constructor without reusing existing constructor, that can be error-prone.
Upvotes: 2
Reputation: 533492
DRY = Don't Repeat Yourself. This doesn't just reduce the code, but makes understanding the code easier. You can see that constructor with one argument is the same as calling the other with an extra zero. In more complex examples, this makes more difference.
WET = Write Everything Twice ;)
Upvotes: 7
Reputation: 3023
Computers today are so fast that invoking additional methods for the sake of readability and removing code redundancy is much more appreciative than having complex and duplicative code which no one can understand.
Programming is not just coding, but much more than that. You have to tell a story through your code to the people who will read your code. Clean code is the recommended way to go.
So if calling a constructor from another constructor is saving 10 lines of code, its much better. And compilers today are so smart that they will generate a very efficient byte/machine code for such scenarios.
Upvotes: 11
Reputation: 8652
because it is better than code duplication that you would have if you wont do it
public class Apples {
String color;
int quantity;
public Apples(String color, int quantity) {
this.color = color;
this.quantity = quantity;
}
public Apples(String color) {
this.color = color; // code duplication
this.quantity = 0;
}
}
Upvotes: 4