This is my last post in series of Java coding standards posts. It focuses on best practices or dos and don'ts while coding. I am sure these good practices once observed while writing code will make your Java code consistent and in most cases bugs free. If you make these practices a habit, it ensures better code quality,less rework and robustness of one's application.
Here goes the list:
·Put each class in a separate file (except where a private class is used exclusively by one class only and also when using inner classes and anonymous classes).
·Use relative path with respect to the location of the execution directory.
·No Compiler warnings / Exceptions should be allowed in the final source code.
·Declare all class variables in one place (at the top of the class).
·Initialize the class/instance variables in default constructor or with declaration.
· Initialize all local variables where they are declared.
·Put declaration only at the beginning of the blocks. Don't wait to declare the variables to until where they are first used (one exception is indexes to loops).
·Avoid using an object to access a class (static) variable or method. Use a class name instead.
·Numerical constants (literals) should not be coded directly, except for -1, 0 and 1, which can appear in a for loop as counter values.
·Avoid assigning several variables to the same value in a single statement. It is hard to read.
·Do not use embedded assignments in an attempt to improve run-time performance. It is the job of the compiler. Example:
d = ( a = b + c) + f; //Avoid
Should be written as
a = b + c;
d = a + f;
· Generally prefer long to int, and double to float. But use int for compatibility with standard Java constructs and classes.
·Minimize direct internal access to instance variables inside methods. Use protected access and update methods instead.
·Prefer declaring arrays as Type[] arrayName rather than Type arrayName[].
·Ensure that non-private statics have sensible values even if no instances are ever created. Use static initializers if necessary.
·Define return types as void unless they return results that are not accessible otherwise
·Avoid hard coding. If hard coding is inevitable due to functionality, give proper comments.
· Constants specific to a class/module should be part of interfaces related to that domain. All constants must relate to some domain specific grouping. If at all possible the interfaces that define globals should be located with the classes which they would operate on.
·Variables for local use should not be declared global.
·Method Names, variable names, class names should be meaningful.
Give proper names for methods, variables, class names focusing on
Maintainability, Readability.
·Variables should be named in such a way that it conveys the actual usage of thevariable.
·All get methods should return a value.
·All set methods should accept values.
·Vector, Array position specific code should not be present.
·Similar methods/parts of code in different classes should be refactored.
·Code inside a method should exactly serve the purpose.
For example, a method written for validation should not do any focus/tab setting.
·The method/variable should be declared as private if it isn't used outside the current class.
·Avoid NullPointerException by checking the input parameters for null in a method and throwing an IllegalArgumentException with the appropriate message.
·If the code in the constructor is too large, logical parts should be separated out into methods.
·If a particular piece of logic is repeated in a class, make a private static method and move that logic in that. If the logic is shared across different classes, then it should be moved in some utility class.
·Make use of appropriate data structure Collection - unordered objects, List - ordered objects, Set - unique objects, HashMap - unordered key- value pairs, LinkedHashMap - ordered key-value pairs.
·Use inline comments for all complex calculations or business logics.
·Check for unnecessary code like System.out.printlns in the code.
·Avoid using Strings in double quoted form. Declare a local private static final constant variable for that.
·Use a Iterator class for iterating a Collection, List or Set instead of using a for( ; ; ) loop. This would make the code more consistent.
·Implementation should be based on proper abstraction. Use Interfaces and abstract classes for hiding the implementation from the client code.
·Try and identify the immutable attributes of your classes and make them final member variables assigned in the constructor. This can prevent some coding errors.
·Always override hashCode method when you override equals. Failure to do so will result in violation of the general contract for Object.hashCode which will prevent your class from functioning properly with conjunction with all hash-based collections, including HashMap, HashSet and HashTable
·Return zero-length arrays instead of nulls. Can prevent null pointer exceptions or complicated if (results == null) tests.
·Try to avoid returning null from methods. Consider the NULL Object pattern as a replacement for returning Null. E.g create a static final constant class instance to represent an empty/null object. E.g Within the Employee interface public static final Employee NULL = new Employee(); So now the calling client code can test for if (Employee.NULL == result). Leads to clearer code and removes some potential for null pointer issues.
·Refer to objects by their interfaces if appropriate interface exists.
·Choose interfaces over abstract classes. If you know something is going to be a base class, your first choice should be to make it an interface, and only if you're forced to have method definitions or member variables should you change it to an abstract class. An interface talks about what the client wants to do, while a class tends to focus on (or allow) implementation details.
·First make it work, then make it fast. This is true even if you are certain that a piece of code is really important and that it will be a principal bottleneck in your system. Don't do it. Get the system going first with as simple a design as possible. Then if it isn't going fast enough, profile it. You'll almost always discover that "your" bottleneck isn't the problem. Save your time for the really important stuff.
·Watch for switch statements or chained if-else clauses. This is typically an indicator of type-check coding, which means that you are choosing what code to execute based on some kind of type information (the exact type may not be obvious at first). You can usually replace this kind of code with inheritance and polymorphism; a polymorphic method call will perform the type checking for you and allow for more reliable and easier extensibility. For Example-
·From a design standpoint, look for and separate things that change from things that stay the same. That is, search for the elements in a system that you might want to change without forcing a redesign, then encapsulate those elements in classes.
·Keep scopes as small as possible so the visibility and lifetime of your objects are as small as possible.
·A class should only one reason to change. Attempt to keep your classes cohesive. E.g. to only do one thing and model one abstraction.
·Try to understand the Open-Closed principle when designing classes. Classes should be open for extension, but closed for modification. Basically, if you need to open up your classes to add new requirements / functions this is likely to indicate that you have not modeled the domain / abstractions correctly. Interfaces, Abstract base classes are all tools you can use to correctly model and abstract the domain requirements.
·Try to understand the Liskov substitution principle. Ok, nice name - good at the interviews. However, the underlying principle is sound. All subtypes must be substitutable for their base types. If you create subtypes you must ensure that if they are used in the same context as the base class that their behavior is predicable. E.g. in sub classing a type do not change its basic type behavior. Inherit because you are of that type not because you simply need some underlying common behavior.
·If there are no formalized code reviews try to discuss your design concepts and code with other team members. Even if they have the same / less experience than you. Sometimes the act of talking something out load can highlight good and bad elements in your code.
Here goes the list:
·Put each class in a separate file (except where a private class is used exclusively by one class only and also when using inner classes and anonymous classes).
·Use relative path with respect to the location of the execution directory.
·No Compiler warnings / Exceptions should be allowed in the final source code.
·Declare all class variables in one place (at the top of the class).
·Initialize the class/instance variables in default constructor or with declaration.
· Initialize all local variables where they are declared.
·Put declaration only at the beginning of the blocks. Don't wait to declare the variables to until where they are first used (one exception is indexes to loops).
·Avoid using an object to access a class (static) variable or method. Use a class name instead.
·Numerical constants (literals) should not be coded directly, except for -1, 0 and 1, which can appear in a for loop as counter values.
·Avoid assigning several variables to the same value in a single statement. It is hard to read.
·Do not use embedded assignments in an attempt to improve run-time performance. It is the job of the compiler. Example:
d = ( a = b + c) + f; //Avoid
Should be written as
a = b + c;
d = a + f;
· Generally prefer long to int, and double to float. But use int for compatibility with standard Java constructs and classes.
·Minimize direct internal access to instance variables inside methods. Use protected access and update methods instead.
·Prefer declaring arrays as Type[] arrayName rather than Type arrayName[].
·Ensure that non-private statics have sensible values even if no instances are ever created. Use static initializers if necessary.
·Define return types as void unless they return results that are not accessible otherwise
·Avoid hard coding. If hard coding is inevitable due to functionality, give proper comments.
· Constants specific to a class/module should be part of interfaces related to that domain. All constants must relate to some domain specific grouping. If at all possible the interfaces that define globals should be located with the classes which they would operate on.
·Variables for local use should not be declared global.
·Method Names, variable names, class names should be meaningful.
Give proper names for methods, variables, class names focusing on
Maintainability, Readability.
·Variables should be named in such a way that it conveys the actual usage of thevariable.
·All get methods should return a value.
·All set methods should accept values.
·Vector, Array position specific code should not be present.
·Similar methods/parts of code in different classes should be refactored.
·Code inside a method should exactly serve the purpose.
For example, a method written for validation should not do any focus/tab setting.
·The method/variable should be declared as private if it isn't used outside the current class.
·Avoid NullPointerException by checking the input parameters for null in a method and throwing an IllegalArgumentException with the appropriate message.
·If the code in the constructor is too large, logical parts should be separated out into methods.
·If a particular piece of logic is repeated in a class, make a private static method and move that logic in that. If the logic is shared across different classes, then it should be moved in some utility class.
·Make use of appropriate data structure Collection - unordered objects, List - ordered objects, Set - unique objects, HashMap - unordered key- value pairs, LinkedHashMap - ordered key-value pairs.
·Use inline comments for all complex calculations or business logics.
·Check for unnecessary code like System.out.printlns in the code.
·Avoid using Strings in double quoted form. Declare a local private static final constant variable for that.
·Use a Iterator class for iterating a Collection, List or Set instead of using a for( ; ; ) loop. This would make the code more consistent.
·Implementation should be based on proper abstraction. Use Interfaces and abstract classes for hiding the implementation from the client code.
·Try and identify the immutable attributes of your classes and make them final member variables assigned in the constructor. This can prevent some coding errors.
·Always override hashCode method when you override equals. Failure to do so will result in violation of the general contract for Object.hashCode which will prevent your class from functioning properly with conjunction with all hash-based collections, including HashMap, HashSet and HashTable
·Return zero-length arrays instead of nulls. Can prevent null pointer exceptions or complicated if (results == null) tests.
·Try to avoid returning null from methods. Consider the NULL Object pattern as a replacement for returning Null. E.g create a static final constant class instance to represent an empty/null object. E.g Within the Employee interface public static final Employee NULL = new Employee(); So now the calling client code can test for if (Employee.NULL == result). Leads to clearer code and removes some potential for null pointer issues.
·Refer to objects by their interfaces if appropriate interface exists.
·Choose interfaces over abstract classes. If you know something is going to be a base class, your first choice should be to make it an interface, and only if you're forced to have method definitions or member variables should you change it to an abstract class. An interface talks about what the client wants to do, while a class tends to focus on (or allow) implementation details.
·First make it work, then make it fast. This is true even if you are certain that a piece of code is really important and that it will be a principal bottleneck in your system. Don't do it. Get the system going first with as simple a design as possible. Then if it isn't going fast enough, profile it. You'll almost always discover that "your" bottleneck isn't the problem. Save your time for the really important stuff.
·Watch for switch statements or chained if-else clauses. This is typically an indicator of type-check coding, which means that you are choosing what code to execute based on some kind of type information (the exact type may not be obvious at first). You can usually replace this kind of code with inheritance and polymorphism; a polymorphic method call will perform the type checking for you and allow for more reliable and easier extensibility. For Example-
interface IVehicle{
void drive(Car car);
}
class Car {
// These Car classes could as easily be interfaces, with no impact on the examples.
// members
}
class HondaCar extends Car {
// members
}
class BMWCar extends Car {
// members
}
Good Practice
class Car implements IVehicle {
public void drive(HondaCar car){
// handle standard drive
}
public void drive(BMWCar car){
// handle BMW car
}
}
Bad Practice
class Car implements IVehicle {
public void drive(Car car){
if(car instanceOf HondaCar )
// perform HondaCar logic
}
if(car instanceOf BMWCar)
// perform BMWCar logic
}
}
·From a design standpoint, look for and separate things that change from things that stay the same. That is, search for the elements in a system that you might want to change without forcing a redesign, then encapsulate those elements in classes.
·Keep scopes as small as possible so the visibility and lifetime of your objects are as small as possible.
·A class should only one reason to change. Attempt to keep your classes cohesive. E.g. to only do one thing and model one abstraction.
·Try to understand the Open-Closed principle when designing classes. Classes should be open for extension, but closed for modification. Basically, if you need to open up your classes to add new requirements / functions this is likely to indicate that you have not modeled the domain / abstractions correctly. Interfaces, Abstract base classes are all tools you can use to correctly model and abstract the domain requirements.
·Try to understand the Liskov substitution principle. Ok, nice name - good at the interviews. However, the underlying principle is sound. All subtypes must be substitutable for their base types. If you create subtypes you must ensure that if they are used in the same context as the base class that their behavior is predicable. E.g. in sub classing a type do not change its basic type behavior. Inherit because you are of that type not because you simply need some underlying common behavior.
·If there are no formalized code reviews try to discuss your design concepts and code with other team members. Even if they have the same / less experience than you. Sometimes the act of talking something out load can highlight good and bad elements in your code.
1 comments :
I don't understand while we should prefer long to int ?
Post a Comment