This is the sixth post based on the book Effective Java by Joshua Bloch. In the previous post we read about best practices to write good methods in Java.
This post covers General Programming practices which will help writing good quality code.
This post covers General Programming practices which will help writing good quality code.
Minimize the scope of the local variables
Declare variables at the last possible moment. Defining variables
before they are really required can mean that the scope of the variable may
turn out to be more than necessary, it may inadvertently be used before it is
logically initialized, it can be used accidently after its scope has finished.
All of these can have disastrous impact on the application. Also somebody
reading the code can tend to forget the type of the variable if it is used far
away from where it is declared.
Every local variable should contain an initializer. The only exceptions
can be variables which are required in the finally block when exceptions are
handled.
Know and use the libraries
It is important to learn the libraries available and leverage them.
Libraries including standard Java library are changing and becoming more
powerful as time progresses and unless one keeps track of the changes one would
end up performing unnecessary coding to achieve something which can be better
done by some library method.
Understand and then keep abreast of changes to at least java.lang,
java.util and java.io.
Avoid float and double if exact answers are required
The float and double types will not give precise values. They are not
suited for monetary calculations. Rounding off will also not help. Use
BigDecimal or int or long for monetary calculations.
Also when using BigDecimal ensure to instantiate as follows:
BigDecimal tenPaise = new BigDecimal(“0.1”);
not
BigDecimal tenPaise = new BigDecimal(0.1);
Note that in the second case we end up using a float value
inadvertently and this will result in the BigDecimal getting a value close to
0.1 and not exactly 0.1, whereas in the first case since we have used a String
as the parameter it will give a precise value of 0.1.
Avoid Strings where other types are more appropriate
Do not use String type variables to represent data which is actually of
a different data type. E.g. when data is received from a browser or read from a
file it typically is in the form of a string and one tends to carry forward the
same till it is necessary to deal with the actual data type. Instead convert the
strings to the correct data type at the first opportunity and convert them back
into strings only at the last possible moment.
Do not concatenate string representation of strings to form a key for a
Map. Instead use a helper class which implements the correct equals and
hashCode method to contain the fields that are required for the key.
Beware the Performance of String Concatenation
Using the “+” operator to concatenate strings is a big overhead.
Instead use a StringBuffer if one needs the variable to be thread safe or
better still use StringBuilder if one is sure that it is not necessary for the
variable to be thread safe.
Additionally prime the StringBuffer or StringBuilder with the expected
size it is expected to grow to if it is possible.
Prefer Interfaces to Reflection
Reflection in Java is a very powerful feature which allows one to
interact with the objects at runtime by discovering what the object supports
and using them.
But this comes at a cost and should be avoided as far as possible.
Instead of reflection one should consider use of Interfaces.
Reflection comes with the following disadvantages:
1.
All benefits of compile time checking is lost.
2.
The code required to perform reflective access
is clumsy and verbose.
3.
Performance of code using reflection will be
slower than code that does not use reflection
If the issue to determine the class at runtime then one should define
an interface, use the interface in the code and at run time use reflection to
instantiate the class (factory pattern). This way we can keep reflection to the
minimum while retaining benefits that accrue with usage of interfaces.
Note that all Object Relation
Mapping libraries use reflection.
Use Native Methods Judiciously
Java provides a way to execute native code. This was used to
get better performance and/or to use some native library functions. But given
the progress that JVM has made one should use native calls if and only if that
is the last resort to use a library that is available only in the native
format. It is not worth the trouble of using native calls for improved
performance.
Optimize Judiciously
Many a times the developers have the tendency to optimize as
they are writing the code. Here are some aphorisms about optimization that
should be known and adhered to by all:
1.
More computing sins are committed in the name of
efficiency (without necessarily achieving it) than for any other single reason
– including blind stupidity. William A Wulf
2.
We should forget about small efficiencies, say
about 97% of the time: premature optimization is the root of all evil. Donald
E. Knuth
3.
We follow two rules in matter of optimization
a.
Rule 1: Don’t do it
b.
Rule 2 (for experts only): Don’t do it yet –
that is not until you have a perfectly clear and unoptimized solution.
M.
A. Jackson
Corollary is “Strive to write good programs rather than fast ones”.
But the same time
1.
Strive to avoid design decisions that limit
performance. It is difficult to change APIs, wire-level protocols, and
persistent data formats. These should be considered carefully at design time to
provide good performance right at the start.
2.
Consider performance consequences of your API
decisions.
3.
Measure performance before and after each
attempted optimization.
Adhere to generally accepted naming convention
There is a generally accepted naming convention for the Java language.
Adhere to this naming conventions and avoid violating these unless there is
real reason to do so. It will make the program understandable and maintainable
by a larger audience. Some conventions are
1.
Package names should be in lower case
2.
Package names can have abbreviated words
3.
Class names should start with a Capital letter
4.
Method, Attribute and Variable names should
start with lower case
5.
Typically Acronyms used in Class, Method,
Attribute or Variable names are capitalized although there is no general
agreement on this
6.
Generally Class, Method, Attribute and Variable
names should have full words
7.
Use a Camel Hump notation to separate words in
classname, methods, attributes and variables.
8.
Underscores are used only for constants
9.
Constants are defined with a set of Capital
letters and Underscores
10.
Interfaces are named as classes or as adjectives
ending with “able” or “ible”
11.
One could follow the convention of naming all
interfaces starting with an “I” although this is not a convention that is
followed by all. This avoids the necessity of adding an “Impl” to indicate
implementation of the interface.
12.
All methods that return a Boolean value start
with “is”.
In the next post we will read about best practices in Exception Handling in Java.
In the next post we will read about best practices in Exception Handling in Java.
No comments:
Post a Comment