Java Coding Practices :
1) Prefer returning Empty Collections
instead of Null
If a program is returning a
collection which does not have any value, make sure an Empty collection is
returned rather than Null elements. This saves a lot of “if else” testing on Null Elements.
2) Use Strings carefully
If two Strings are concatenated
using “+” operator in a “for” loop, then it creates a new String Object, every
time. This causes wastage of memory and increases performance time, for this
case can go for StringBuffer. Also, while instantiating a String Object,
constructors should be avoided and instantiation should happen directly. For
example:
//Slower Instantiation
String bad
= new String("Yet
another string object");
//Faster Instantiation
String
good = "Yet another string object"
3) Avoid unnecessary Objects
One of the most expensive operations
(in terms of Memory Utilization) in Java is Object Creation. Thus it is
recommended that Objects should only be created or initialized if necessary.
Following code gives an example:
import java.util.ArrayList;
import
java.util.List;
public
class Employees {
private List Employees;
public List getEmployees() {
//initialize only when required
if(null == Employees) {
Employees = new ArrayList();
}
return Employees;
}
}
4) Dilemma between Array and ArrayList
Developers often find it difficult
to decide if they should go for Array type data structure of ArrayList type.
They both have their strengths and weaknesses. The choice really depends on the
requirements.
1. Arrays have fixed size but
ArrayLists have variable sizes. Since the size of Array is fixed, the memory
gets allocated at the time of declaration of Array type variable. Hence, Arrays
are very fast. On the other hand, if we are not aware of the size of the data,
then ArrayList is More data will lead to ArrayOutOfBoundException and less data
will cause wastage of storage space.
2.It
is much easier to Add or Remove elements from ArrayList than Array
3.Array can be multi-dimensional but
ArrayList can be only one dimension.
5) Check Oddity
Have a look at the lines of code
below and determine if they can be used to precisely identify if a given number
is Odd?
public
boolean oddOrNot(int num) {
return num % 2 == 1;
}
These lines seem correct but they
will return incorrect results one of every four times (Statistically speaking).
Consider a negative Odd number, the remainder of division with 2 will not be 1.
So, the returned result will be false which is incorrect!
This can be fixed as follows:
public
boolean oddOrNot(int num) {
return (num & 1) != 0;
}
Using this code, not only is the
problem of negative odd numbers solved, but this code is also highly optimized.
Since, Arithmetic and Logical operations are much faster compared to division
and multiplication, the results are achieved faster so in second snippet.
6) Difference between single quotes and
double quotes
public class Haha {
public static void main(String args[]) {
System.out.print("H" +
"a");
System.out.print('H' + 'a');
}
}
From the code, it would seem return
“HaHa” is returned, but it actually returns Ha169. The reason is that if double
quotes are used, the characters are treated as a string but in case of single
quotes, the char -valued operands ( ‘H’ and ‘a’ ) to int values through a
process known as widening primitive conversion. After integer conversion, the
numbers are added and return 169.
7) Avoiding
Memory leaks by simple tricks
Memory leaks often cause performance
degradation of software. Since, Java manages memory automatically, the
developers do not have much control. But there are still some standard
practices which can be used to protect from memory leakages.
·Always release database connections when querying is
complete.
·Try to use Finally block as often possible.
·Release instances stored in Static Tables.
8) Reserve
memory for Java
Some of the Java applications can be
highly CPU intensive as well as they need a lot of RAM. Such applications
generally run slow because of a high RAM requirement. In order to improve
performance of such applications, RAM is reserved for Java. So, for example, if
we have a Tomcat webserver and it has 10 GB of RAM. If we like, we can allocate
RAM for Java on this machine using the following command:
export JAVA_OPTS="$JAVA_OPTS
-Xms5000m -Xmx6000m -XX:PermSize=1024m -XX:MaxPermSize=2048m"
|
Xms
= Minimum memory allocation pool
Xmx
= Maximum memory allocation pool
XX:PermSize
= Initial size that will be allocated during startup of the JVM
XX:MaxPermSize
= Maximum size that can be allocated during startup of the JVM
9) How to time
operations in Java
There are two standard ways to time
operations in Java: System.currentTimeMillis() and System.nanoTime() The
question is, which of these to choose and under what circumstances. In
principle, they both perform the same action but are different in the following
ways:
1.System.currentTimeMillis takes
somewhere between 1/1000th of a second to 15/1000th of a second (depending on
the system) but System.nanoTime() takes around 1/1000,000th of a second (1,000
nanos)
2.System.currentTimeMillis takes a few
clock cycles to perform Read Operation. On the other hand, System.nanoTime()
takes 100+ clock cycles.
3.System.currentTimeMillis reflects
Absolute Time (Number of millis since 1 Jan 1970 00:00 (Epoch Time)) but
System.nanoTime() does not necessarily represent any reference point.
10) Choice between Float and Double
Data type
|
Bytes used
|
Significant figures
(decimal)
|
Float
|
4
|
7
|
Double
|
8
|
15
|
Double is often preferred over float
in software where precision is important because of the following reasons:
Most processors take nearly the same
amount of processing time to perform operations on Float and Double. Double
offers far more precision in the same amount of computation time.
11) Computation of power
To compute power (^), java performs
Exclusive OR (XOR). In order to compute power, Java offers two options:
1.Multiplication:
1
|
double square = double a *
double
a;
// Optimized
|
2
|
double cube = double a *
double a * double
a;
// Non-optimized
|
3
|
double cube = double a *
double
square;
// Optimized
|
4
|
double quad = double a *
double a * double a * double
a; //
Non-optimized
|
5
|
double
quad = double square * double
square;
// Optimized
|
2.pow(double base, double exponent):‘pow’ method is used to calculate where multiplication is
not possible (base^exponent)
1
|
double
cube = Math.pow(base, exponent);
|
Math.pow should be used ONLY when
necessary. For example, exponent is a fractional value. That is because
Math.pow() method is typically around 300-600 times slower than a
multiplication.
12) How to handle Null Pointer Exceptions
Null Pointer Exceptions are quite
common in Java. This exception occurs when we try to call a method on a Null
Object Reference. For example,
1
|
int noOfStudents
= school.listStudents().count;
|
If in the above example, if get a
NullPointerException, then either school is null or listStudents() is Null.
It’s a good idea to check Nulls early so that they can be eliminated.
1
|
private int getListOfStudents(File[] files) {
|
|||
2
|
if (files == null)
|
|||
3
|
throw new NullPointerException("File
list cannot be null");
|
|||
4
|
}
|
|||
13) Encode in JSON
JSON (JavaScript Object Notation) is
syntax for storing and exchanging data. JSON is an easier-to-use alternative to
XML. Json is becoming very popular over internet these days because of its
properties and light weight. A normal data structure can be encoded into JSON
and shared across web pages easily. Before beginning to write code, a JSON
parser has to be installed.
14) Simple String Search
Java offers a Library method called
indexOf(). This method is used with String Object and it returns the position
of index of desired string. If the string is not found then -1 is returned.
public
class StringSearch {
public static void main(String[] args) {
String myString = "I am a
String!";
if(myString.indexOf("String")
== -1) {
System.out.println("String not
Found!");
}
else {
System.out.println("String
found at: " + myString.indexOf("String"));
}
}
}
14) Measuring time
Many applications require a very
precise time measurement. For this purpose, Java provides static methods in
System class:
1.currentTimeMillis(): Returns current time in MilliSeconds
since Epoch Time, in Long.
1
|
long startTime =
System.currentTimeMillis();
|
|
2
|
long
estimatedTime = System.currentTimeMillis() - startTime;
|
2.nanoTime(): Returns
the current value of the most precise available system timer, in nanoseconds,
in long. nanoTime() is meant for measuring relative time interval instead of
providing absolute timing.
1
|
long startTime =
System.nanoTime();
|
|
2
|
long
estimatedTime = System.nanoTime() - startTime;
|
15) Avoid Floating Point Numbers
Floating point numbers should be
used only if they are absolutely necessary. For example, representing Rupees
and Paise using Floating Point numbers can be Problematic – BigDecimal should
instead be preferred. Floating point numbers are more useful in measurements.
16) 5 class design principles [S.O.L.I.D.] in java
Classes are the building blocks of
your java application. If these blocks are not strong, your building (i.e.
application) is going to face the tough time in future. This essentially means
that not so well-written can lead to very difficult situations when the
application scope goes up or application faces certain design issues either in
production or maintenance.
SOLID
Class Design Principles:
I)
Single Responsibility
Principle : i.e
"One class should have one
and only one responsibility"
In other words, you should write,
change and maintain a class for only one purpose. If it is model class then it
should strictly represent only one actor/ entity. This will give you the
flexibility to make changes in future without worrying the impacts of changes
for another entity.
Similarly, If you
are writing service/manager class then it should contain only that part of
method calls and nothing else. Not even utility global functions related to
module. Better separate them in another globally accessible class file. This
will help in maintaining the class for that particular purpose, and you can
decide the visibility of class to specific module only.
ii)
Open Closed Principle
This is second
important rule which you should keep in mind while designing your application.
It says:
"Software components should
be open for extension, but closed for modification"
What does it
mean?? It means that your classes should be designed such a way that whenever
fellow developers wants to change the flow of control in specific conditions in
application, all they need to extend your class and override some functions and
that’s it.
If other
developers are not able to design desired behavior due to constraints put by
your class, then you should reconsider changing your class. I do not mean here
that anybody can change the whole logic of your class, but he/she should be
able to override the options provided by software in unharmful way permitted by
software.
For example, if
you take a look into any good framework like struts or spring, you will see
that you can not change their core logic and request processing, BUT you modify
the desired application flow just by extending some classes and plugin them in
configuration files.
Iii)
Liskov’s Substitution
Principle
This principle is
a variation of previously discussed open closed principle. It says:
"Derived types must be
completely substitutable for their base types"
It means that the classes fellow
developer created by extending your class should be able to fit in application
without failure. I.e. if a fellow developer poorly extended some part of your
class and injected into framework/ application then it should not break the
application or should not throw fatal exceptions.
This can be
insured by using strictly following first rule. If your base class is doing one
thing strictly, the fellow developer will override only one feature incorrectly
in worst case. This can cause some errors in one area, but whole application
will not do down.
iv)
Interface Segregation
Principle
This principle is
my favorite one. It is applicable to interfaces as single responsibility
principle holds to classes. It says:
"Clients should not be
forced to implement unnecessary methods which they will not use"
Take an example. Developer Alex
created an interface Reportable and added two methods generateExcel() andgeneratedPdf(). Now client ‘A’ wants to use this
interface but he intend to use reports only in PDF format and not in excel.
Will he achieve the functionality easily.
NO. He will have
to implement two methods, out of which one is extra burden put on him by designer
of software. Either he will implement another method or leave it blank. So are
not desired cases, right??
So what is the solution? Solution is
to create two interfaces by breaking the existing one. They should be likePdfReportable and ExcelReportable. This will give the flexibility to
user to use only required functionality only.
v)
Dependency Inversion
Principle
Most of us are
already familiar with the words used in principle’s name. It says:
"Depend on abstractions, not
on concretions"
In other words. you should design your
software in such a way that various modules can be separated from each other
using an abstract layer to bind them together. The classical use of this
principle of BeanFactory in spring framework. In spring framework, all modules are
provided as separate components which can work together by simply injected
dependencies in other module. They are so well closed in their boundaries that
you can use them in other software modules apart from spring with same ease.
This has been
achieved by dependency inversion and open closed principles. All modules expose
only abstraction which is useful in extending the functionality or plugin in
another module.
These were five class design principles which makes the best practices
to be followed to design your application classes. Let me know of your
thoughts.
Exception Handling Best Practise’s :
17) Never swallow the exception in
catch block
catch (NoSuchMethodException e) {
return null; // it is swalloing the Exception Never Do this
}
|
18) Declare the specific checked exceptions that
your method can throw
public void foo() throws Exception { //Incorrect
way
}
public void foo() throws SpecificException1,
SpecificException2 { //Correct way
}
19)
Always correctly wrap the exceptions in custom
exceptions so that stack trace is not lost
catch (NoSuchMethodException e) {
throw new MyServiceException("Some information: " + e.getMessage()); //Incorrect way
}
|
This destroys the
stack trace of the original exception, and is always wrong. The correct way of
doing this is:
catch (NoSuchMethodException e) {
throw new MyServiceException("Some information: " , e); //Correct way
}
|
20)
Either log the exception or throw it but never do
the both
catch (NoSuchMethodException e) {
LOGGER.error("Some information", e);
throw e;
}
|
As in above
example code, logging and throwing will result in multiple log messages in log
files, for a single problem in the code, and makes life hell for the engineer
who is trying to dig through the logs.
21)
Never throw any exception from finally block
try {
someMethod(); //Throws exceptionOne
} finally {
cleanUp(); //If finally also threw any exception the
exceptionOne will be lost forever
}
|
This is fine, as
long as cleanUp() can never throw any exception. In the above example, if
someMethod() throws an exception, and in the finally block also, cleanUp()
throws an exception, that second exception will come out of method and the
original first exception (correct reason) will be lost forever. If the code
that you call in a finally block can possibly throw an exception, make sure
that you either handle it, or log it. Never let it come out of the finally
block.
22)
Always catch only those exceptions that you can
actually handle
catch (NoSuchMethodException e) {
throw e; //Avoid this as it doesn't help anything
}
|
23)
Don’t use printStackTrace() statement or similar methods
24)
Use finally blocks instead of catch blocks if you
are not going to handle exception
try {
someMethod(); //Method 2
} finally {
cleanUp(); //do cleanup here
}
|
This is also a
good practice. If inside your method you are accessing some method 2, and
method 2 throw some exception which you do not want to handle in method 1, but
still want some cleanup in case exception occur, then do this cleanup in
finally block. Do not use catch block.
25) How to create an instance of any class without using new keyword
1)Using newInstance method of
Class class
Class ref
= Class.forName("DemoClass");
DemoClass obj =
(DemoClass) ref.newInstance();
2) Using class loader’s loadClass()
instance.getClass().getClassLoader().loadClass("NewClass").newInstance();
3) Using clone() of java.lang.Object
NewClass obj = new NewClass();
NewClass obj2 = (NewClass)
obj.clone();
4) Using Object serialization and deserialization
ObjectInputStream objStream =
new ObjectInputStream(inputStream);
NewClass obj = (NewClass )
inStream.readObject();
5)Using Reflection
constructor.newInstance(); or
class.newInstance();
26) Internal caching in wrapper
classes
Wrapper classes are immutable in java, Right? “YES”. So, like
string pool, they can also have their pool, right? “Great Idea”. Well, it’s
already there. JDK provided wrapper classes also provide this in form of
instance pooling i.e. each wrapper class store a list of commonly used
instances of own type in form of cache and whenever required, you can use them
in your code. It helps in saving lots of byes in your program runtime.
27)
Always
use length() instead of equals() to check empty string in java
In your day-to-day programming
activities, you must be coming across multiple situation where you need to
check if a string is empty. There are various ways to do this and some
use string1.equals(“”).
NEVER do this.
Best way to check if string is
empty or not is to use length() method. This method simply return the count of characters
inside char array which constitutes the string. If the count or length is 0;
you can safely conclude that string is empty.
28) Performance comparison of
different for loops in java
Initialize
another local variable with size
private static
List<Integer> list = new ArrayList<>();
int size = list.size();
for(int j = 0; j
< size ; j++){
//do stuff
}
Initialize the
initial value of counter to size of list
private static
List<Integer> list = new ArrayList<>();
for(int j =
list.size(); j > size ; j--){
//do stuff
}
29) Finding Time Estimations/
Performance of any Statement Executions in java
private static
long startTime;
private static
long endTime;
startTime
= Calendar.getInstance().getTimeInMillis();
/*
provide
any executable statement
for(Integer
i : list){
//
}*/
endTime =
Calendar.getInstance().getTimeInMillis();
System.out.println("For each loop
:: " + (endTime - startTime) + " ms");
30)
Wrapper
Caches like as String Cache in java :
public static
void main(String[] args) {
Integer a1 = 100;
Integer a2 = 100;
Integer a3 = new Integer(100);
System.out.println(a1 == a2);
System.out.println(a1 == a3);
}
31) for more refer
Other Coding standards
-----------------------
1) Javadoc comments should be added to the class as well as the methods.
2) Unused member variables should not be present in the classes.
3) Proper catch blocks should be added for exception handling instead of single Exception object handler.
4) Proper naming conventions should be used for variables, method and class names.
5) Instead of using hard coded strings, constants should be declared in a separate Constants class.
6) All database and file handlers should be properly closed when there is no further need for them.
7) No trailing spaces should be present in code lines.
8) Uniform coding standards for braces, loops, if-else, switch should be used across the application.
9) If similar logic is being used at multiple places then it should be declared in a helper class and called from multiple places.
10) A single method should not exceed 100 lines of code as it becomes difficult to maintain beyond that.
Split a single big method into multiple smaller methods.
11) Usage of API classes and methods should be encouraged instead of writing custom code for performing the same operations.
12) A single statement should not go beyond the viewable area of the editor or IDE and should be split across multiple lines.
13) Extra emphasis should be given on writing the unit test cases for the code which is going to be released.
14) The addition of any piece of code should not break existing functionality.
15) Usually a single database transaction can be done by writing the SQL query in multiple ways and there is a huge
difference in the performance of database transactions depending upon the way in which SQL query is written.
16) If a class has many member variables and the instance of that class can be initialized by initializing
only a partial number of variables then it is better to have static factory methods for initializing the
member variables instead of overloading the constructors.
17) Creating immutable class should be encouraged than mutable classes.
18) The best way to check if the String object is neither null nor empty string is to use the following code: if(“”.equals(str))
19) Add appropriate access specifiers to methods instead of marking all methods in a class as public.
20) Follow best practices suggested by any framework/library being used in the application like Spring, Struts, Hibernate, jQuery.