My question is I can reuse the more general addProperty(Property p) method within the other 2 addProperty methods.
In general, yes. There is nothing inherently wrong with having one method effectively wrap another (regardless of whether it's an overload or not). If a significant portion of the overloaded method bodies would otherwise be repeating themselves anyway, doing this actually follows DRY principles to a tee.
However, in this case, the second and third method shouldn't exist because they are nothing more than a wrapper around a Property constructor. This violates DRY: if the Property constructor changes, so must this method, for no apparent reason other than "because I created this method".
Whoever would call any of these methods (i.e. the consumer) would have access to the Property constructors, which means they are already able to figure out which parameters are needed. Your second and third method are just repeating the same information. It adds nothing of value, but it becomes a WET spot in case the Property constructor changes.
I'm mainly considering how calling the 1st addProperty method within the other's requires 2 object initializations.
Even if your consumer calls the first method, they are still doing two initializations:
- The object that will the passed into the
addProperty(Property p) method parameter - The
new Property(p) that you instantiate inside this method
Your concern may be valid but it's the same for all three methods, so it does not matter for your particular question here.
I'm not quite sure why you do
properties[currentPropertyIndex] = new Property(p);
instead of
properties[currentPropertyIndex] = p;
I suspect you're cloning the object so that the consumer can no longer make changes to it after it was added. Whether that's necessary of not isn't clear to me. If it is necessary, then that second instantiation is the cost of implementing the cloning.
While if I rewrote the method body for each addProperty it would only require 1 object initialization.
You could avoid a second instantiation if you only use the second or third method, but good practice tends to suggest wrapping a set of data values (that belong together) in an object anyway. Complying with good practice inherently leads you back to your double initialization, and this double initialization isn't a red flag for performance (assuming there's no heavy lifting in the constructor's body).
Your performance argument of avoiding one object instantiation pretty much bleaks in comparison with the readability and general not-nice-to-develop consequences of using methods with long signatures.
in larger applications would this make a difference to performance or slow down garbage collection?
Not to a degree that you should generally steer away from it. Unless you are squeezing for performance, these kinds of considerations add an unnecessary complexity the codebase for negligent gains (if any).
Don't optimize prematurely. Optimize when there is a performance issue. It's better to solve the issues that occur in reality rather than any issue you can think of, because the latter is going to lead you to wasting effort on fixing things that maybe never ended up becoming a problem anyway.
intis a totally inappropriate return type for this context. All the negative return values should be replaced by error objects, exception throws, or enum values.