Sundarrajk's Weblog

Archive for the ‘Code Quality’ Category

This is the seventh post in the series of posts based on the book Effective Java by Joshua Bloch. In the previous post we read about General Programming practices to write good code in Java.

This section speaks about the best practices in handling Exception. This is one area that many do not understand properly and many of the problems arise due to lack of handling Exceptions.
Use Exceptions Only for Exceptional Conditions

Do not use exceptions to handle situations which can be handled without exceptions. E.g
try {
    while(true) {
        a[i++] .f();
    }
catch(ArrayIndexOutOfBoundsException e) {
}
Instead use
for (i = 0; i < a.length; i++) {
    a[i].f();
}
Exceptions as the name indicates should be used to handle Exceptional situations; they should never be used for ordinary control flow.
Use checked exceptions for recoverable conditions and run-time exceptions for programming errors

There are three types of exceptions in Java
1.       Checked Exceptions: These are exceptions that can be handled by the client. E.g. IOException, FileNotFoundException.  The compiler will force the user of the API to handle such exceptions. I.e. the user needs to either declare it in the methods throws clause or needs to put the code within a try – catch block where the Exception is handled.
2.       Run Time Exceptions: E.g. ArrayIndexOutOfBoundsException, NullPointerException. These are subclasses of java.lang.RuntimeException. The compiler will not force the user of the API to handle such exceptions.
3.       Errors: These are serious errors from which the users cannot be excepted to recover. OutOfMemoryError is an example of this. These are subclasses of java.lang.Error.
The Checked Exceptions should be mentioned in the throws clause so that the user of the API can handle it or pass it on to its caller to be handled by it.
Runtime exceptions should normally not be thrown or handled. But run-time can be used to indicate programming errors. E.g. one could throw an IllegalArgumentException if any of the parameters passed to the method does not meet the preconditions expected of it.
Errors should normally never be thrown or handled by any method.
Avoid unnecessary use of checked exceptions

 A method should throw as less a number of checked exceptions as possible. Throwing more checked exceptions makes it difficult for the user of the API to use the API and the user ends up handling a generic Exception. Throw checked exceptions if and only if the user of the API can recover from the exception that has been raised.
If some exceptions can be prevented by providing APIs for checking conditions that can throw the exceptions provide this function so that the user can use this API instead of handling a RunTimeException. E.g. if a method of a class can be invoked conditionally then provide a method by which the user can check if the method can be invoked before invoking the method so that we can throw a Run Time exception from the method if there is an issue.
E.g. instead of forcing the user to write a code as follows:
try {
    obj.action(args);
} catch(MethodAccessDeniedException e) {
    //Handle Exception
}
We could provide a method called has Access and allow the user to write  code as
if (obj.hasAccess(args)) {
    obj.action(args);
} else {
    //Handle no access situation
}
If a user invokes obj.action(args) without first checking for has Access then the user may get an RunTimeException.
Throw Exceptions Appropriate to the Abstraction

Sometimes if APIs throw Exceptions which are seemingly out of place it can be very confusing. This typically happens if one were to throw an Exception generated at the lower level directly to the upper level. To avoid this, higher layers should catch lower level exceptions and in their place throw exceptions that are explainable In terms of the higher-level abstraction. When doing this it is important to ensure that the lowest level of Exception and the stack trace associated with it is not lost. This can be achieved by using Exception chaining.
try {
    ….
} catch(LowerLevelException e) {
    throw new HigherLevelException(e);
}

Document all Exceptions thrown by each Method

Always document the exceptions that will be thrown by method. Never use a generic exception like java.lang.Exception or java.lang.Throwable to indicate the Exception thrown. This gives the user of API no idea of what actually is the Exception that is being thrown from the API.
1.       Document every checked Exception that the method can throw using the @throws tag and include them in the throws keyword in the method declaration.
2.       Document every unchecked Exception that the method can throw using the @throws tag, but do not declare it in the throws keyword along with the checked exceptions in the method declaration.
3.       If an exception is thrown by many methods in a class for the same reason then it is not wrong to document this at the class level indicating the reason for the methods throwing this exception.
Include failure-capture information in detail messages

When a program fails due to an unhandled exception the system automatically prints the stack trace which includes the detailed message in the Exception. This will typically be the only information somebody has to figure out what went wrong. So to make this comprehensive the message should contain the all the parameter values and field values that contribute to the exception. One way to ensure that the Exception has all the details required is to create a constructor which forces the user to provide the required information by default.
Strive for failure atomicity

Generally speaking, a failed method should leave the object in the state that it was in prior to the invocation. A method with this property is said to be failure atomic.
The ways to achieve this are
1.       Make the class immutable. This will ensure that the object is never altered irrespective of the exception thrown from any method
2.       Check the parameters and fields for validity before proceeding with the method execution. This will ensure the exception is thrown even before the object is mutated.
3.       Another option is to write a recovery code which can be invoked before an exception is throw to restore the object the state prior to the invocation of the method that is throwing the exception.
4.       The last option is to make a temporary copy of the object and work on it and if no exception occurs restore the new state to the original object. This can be an expensive operation and should be done if an only if really necessary.
This should be avoided if it makes the code more complex or if it drastically reduces the performance of the system.
Don’t ignore Exception

Of an exception is caught then it should be handled correctly. One should not have a code as follows:
try {
    …
} catch (SomeException e) {
}
An empty catch block defeats the purpose of exceptions which is to force the user to handle exceptional situations.
At the minimum have a comment explaining why the exception is being ignored.

In the next post we will read about best practices of using Threads in Java.

Advertisements
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.

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.

This is the fifth in the series of posts based on the book Effective Java by Joshua Bloch. The previous post was about best practices in converting C structures to Java.

This post gives tips and best practices on how to write good methods in the classes.

Check Parameters for Validity

Methods that expect parameters expect the parameters to adhere to certain rules. In all public methods one should validate the parameters to ensure that they adhere to the expected rules and if not they should throw the right exception. It is also important that the constraints on the parameters be well documented.
For private methods we should ensure that we pass only the right attributes and instead of checking and throwing exceptions use Assertions.
It is very important that the parameters to the constructors are validated correctly.
The only exception under which one should not validate the parameters is, when there is a huge overhead in the validation.
Make Defensive Copies when needed

Normally a class should not expect an external class to be able to change the values of its attributes without its knowledge. But when a class contains mutable objects it is easy to allow clients to change the attributes without the class knowing it.
E.g. consider the following class:
public final class Period {
    private final Date start;
    private final Date end;
    public Period(Date start, Date end) {
        if (start.compareTo(end) > 0) {
            throw new IllegalArgumentException(start + “ after “ + end);
        }
        this.start = start;
        this.end = end;
    }
    public Date start() {
        return start;
    }
    public Date end() {
        return end;
    }
}
This class seems to be immutable as the only way to set the values of the start and end dates are through the constructors. But the Date class itself is a mutable class and there are two ways in which the values of the class can be changed:
1.       A client which passes the start and end date to the constructor can hold on the instance of the date and then at a later stage can change the value of these dates using the setYear, setMonth or any of the other methods.
2.       Similarly there is nothing to stop a client from invoking something as Period.start.setYear(someYear).
To avoid these we need to make copies of such mutable classes. In the constructor we can create new Date objects and store them instead of the passed date objects.
    public Period(Date start, Date end) {
        this.start = new Date(start.time());
        this.end= new Date(end.time());
        if (this.start.compareTo(this.end) > 0) {
            throw new IllegalArgumentException(start + “ after “ + end);
        }
    }
Now even if the client changes the objects that it passed to the constructor the values of the dates in the class will not change. Note that the validation was done after the copy was done. This is to prevent the situation where the value of the dates are changed after the validation and before the creation of the new dates in some other thread.
Also the clone method is not used as Date can be subclassed and a subclassed Date cannot be trusted.
Similarly we need to change the start and end methods to:
    public Date start() {
        return start.clone();
    }
    public Date end() {
        return end.clone();
    }
This will ensure that no client will be able to change the start and end attributes of this class. Note that clone has been used here as we are sure that we are using the java.util.Date and not a untrusted subclass of Date.
This is very important if we are writing a library for use by a large audience over which we have no control.
Defensive copying can be avoided if we are working with a set of trusted clients.
Design Method Signatures carefully

The following should be kept in mind when writing methods:
1.       Choose method names carefully: A method name should convey to its user the exact operation it is performing. It should not be necessary to further explain it in the method comments. What will be required in the method comments will be to specify how it can be used and what the parameter constraints are.
2.       Do not go overboard and provide too many convenience methods: Too many makes understanding the class that much difficult and that much more difficult to test. Provide convenience calls only when it is expected that the method will be used frequently. If in doubt do not provide.
3.       Avoid long parameter list: It will be very difficult to use a method which has a large number of parameters even if the users have the benefit of an IDE which prompts for parameters. This is even more problematic if there is sequence of parameters of the same type. Consider creating a helper class or splitting the methods into multiple methods which requires lesser number of parameters.
4.        When a parameter being passed to a method has an interface define the parameter as the interface rather than the concrete class that implements that interface. E.g. if a list is expected as an input specify the parameter of type List rather than specifying it of type ArrayList.
5.       Use Function Objects judiciously: Function Objects have their place in software but when overused it can make understandability of the program very difficult. It is not be shunned but it is to be used only in situations where it makes sense and allows others to understand it easily.
Function Objects are Objects which contain only Functions and no attributes. These are typically used to handle callbacks in Java. E.g. a GUI event handlers, or a class that implements Comparator interface and implements only the compare method.
Use Overloading Judiciously

One needs to be careful when overloading functions and very clear. We need to keep the following rule when we use overloading “selection among overloaded methods is static (i.e. determined at compile time), while selection among overridden methods is dynamic”. So if we overload methods then the method to be executed will be determined at compile time and irrespective of the actual run time datatype the predetermined method will be invoked.
As far as possible avoid having overloaded methods with the same number of parameters. This makes overloading very safe. If one needs to write overloaded methods with the same number of parameters then the parameter types should be very different from each other to avoid confusion.
Return Zero-length Arrays and not nulls

If a method returns an Array and conditionally it returns a null then client that invokes this method needs to check for nulls before proceeding. And if some client were to forget checking for null we will end up with Null Pointer Exception.
Instead if we return a zero length array as the output then no client needs to check for the validity of the array and we can avoid Null Pointer Exceptions.
Note that in most case the clients would have a loop which would be looping through the array and doing some processing and this will be unaffected if one returns a zero-length array.
Write doc comments for all exposed API elements

It is important to document all the public methods and attributes of a class. This will help the users of the class use it in a much better way. It is advisable to also document the protected and private methods if one wishes the code to maintainable.
The method comments must have the following:
1.       What the method does. This should pretty much be clear from the name of the method but in certain scenarios it will help if there is some additional information provided. It should never mention how the method functions.
2.       Do not have two methods or constructors with the same summary description.
3.       It should mention all of the preconditions, i.e. all the conditions that should be true before the method can be invoked.
4.       It should mention all of the postconditions, i.e. all of the things that will be true after the method has been invoked.
5.       It should mention any side effects of invoking the method
6.       The thread safety of the method should be specified especially if it is not thread safe
7.       The purpose of the parameter along with its constraints should be specified
8.       All the exceptions that the method can throw should be documented and if possible with the condition under which it can be thrown
9.       Do not have comments for getters and setters unless something unusual is being done in the method.

In the next post we will read about best General Programming practices.

This is the fourth part in the series of posts based on the book Effective Java by Joshua Bloch. In the previous post we saw best practices of writing good classes and interfaces.

This section talks of how to convert C constructs to Java. The important section that everybody needs to look into is the Replace Enum constructs with Classes. This will apply to everybody trying to create an Enum.

Replace structures with Classes

The world of C has structures to represent complex data types. The equivalent of that in the Object Oriented world are classes. If a structure is translated to a class it will be a simple/trivial class in the Object Oriented world which will have only private attributes will potential getters and setters. Ideally one should not make the members public and use getters and setters as indicated above. Exception can be made if a class is private to a package or to another class the attributes may be made public as any change in the structure of the class will only have limited impact.

Replace unions with class hierarchies

In C it is possible to define Union which can hold more than one type of data or a set of bytes can be interpreted differently depending on the requirement. It is not possible to do this is Java in the same manner, i.e. no class can be used store different types of data at different points in time. Instead one should use a class hierarchy to represent unions. This will ensure that while we have a common interface using which we can access the set of classes each class can hold the different types of data. Some common data may be held in the common class.
Replace enum constructs with classes

Enums are used in C to represent constants values. It is also used to ensure that that only a right parameter value is passed to a function.
Concerting an enum of the type
typedef enum {SPADES, CLUBS, HEARTS, DIAMONDS} suits;
One way this can be implemented in Java is
public class PlayingCard {
    public static final int SUIT_SPADES = 1;
    public static final int SUIT_CLUBS = 2;
    public static final int SUIT_HEARDS = 3;
    public static final int SUIT_DIAMONDS = 4;
}
But in places where we need to pass a Suit Type to a function or get back a suit type we will end up sending an integer or getting back an integer. This does not ensure that we will get a right integer all the time. This problem can be avoided by using classes to define the suits.
E.g. we could create a class as follows:
public class Suit {
    private final String name;
    private Suit(String name) { this.name = name;}
    public static final Suit SPADES = new Suit(“Spades”);
    public static final Suit CLUBS = new Suit(“Clubs”);
    public static final Suit HEARTS = new Suit(“Hearts”);
    public static final Suit DIAMONDS = new Suit(“Diamonds”);
}
Since the constructor is private the developers cannot extend the class and cannot create instance of classes. Now in the places where we need to pass a Suit type or return a Suit type we can use this class. Also since there are only four instances of this class which we have defined we can be assured that we will never get a class other than one of these four. This also means that we can use the simple == operator for comparisons.
Replace Function Pointers with Classes and Interfaces

C has function pointers. This can be used to pass a comparator function to algorithms like qsort. But java does not support function pointers. The solution will involve defining an interface and then implementing a class that implements the interface. So for a qsort algorithm we can use the Comparable interface and define a class which defines the Comparable interface and defines the compare function which can be used by the qsort algorithm implementation.

In the next section we will see best practices in writing good methods in Java.

This is the third part of the series of posts based on the book Effective Java by Joshua Bloch. In the previous post we read about best practices in writing methods which are common to all classes.

This post is all about how to design classes and when and how to leverage the interfaces.

One of the suggestions is to use composition over hierarchy. This will definitely ruffle the feathers of many a hardcore Object Oriented followers. But after about 10 years and more in the Object Oriented world I tend to fully agree with the suggestion. It makes more sense to use composition over inheritance. Inheritance complicates more than it eases the problems. Composition helps keep the code base simple and uncomplicated.

Although the suggestions are basically for Java many of the suggestions applies also to the other Object Oriented Languages.

Minimize the accessibility of classes and members

In a module hide as much internal details as possible from the external world. Expose only that much as is required for the outside world to communicate with this module. This will ensure that that the module is isolated from the other modules interacting with it, making it easier to make changes to this without impacting the others.

Rules for good design of Class

1.       Make the classes and members as inaccessible as possible.
2.       All attributes other than constants (public static final) should be private to the class
3.       It is nearly always wrong to have public static final array field as the contents of the array are still modifiable. Ensure that objects referenced by public static final fields are immutable.

Favour Immutability

Whenever possible create immutable classes. This will ensure that they can be safely shared across multiple threads without worries about synchronization or race conditions.

Rules to make a class immutable

The make a class immutable the following rules need to be adhered to:
1.       Do not provide any method that can modify the object. Typically have only get methods and no set methods.
2.       Ensure that no method can be overridden. This will prevent the sub classes from breaking this rule.
3.       Make all fields final. This will ensure that one cannot change the value of the fields even from within the class.
4.       Make all fields private.
5.       Ensure exclusive access to any mutable components. If the class has to refer to a mutable class then ensure that this mutable class is never exposed outside of the class. If an instance of such an object needs to be returned from the class then make a copy and return the copy so that the original never changes.

Advantage

1.       Immutable classes need not ever be synchronized
2.       Their internals can be exposed without any problem

Disadvantage

1.       The only disadvantage of immutable class is that one needs to instantiate object everytime one needs the object with a different value. Creating too many objects can be a problem.

Best Practices

1.       Classes should be immutable unless there is a very good reason to make them mutable.
2.       If a class cannot be made immutable then the mutability should be limited.
3.       Constructors should create fully initialized objects with all of their invariants established
Favour composition over inheritance

A sub class depends on the implementation details of the super class. If the implementation of the super class changes the functionality of the sub-class is likely to be broken. Given this scenario it is good to go for composition rather than inheritance, except in cases where the class is meant to be sub-classed.

Some rules to follow

1.       Subclass only within a package so that a single set of developers has visibility into both the classes.
2.       Extend when the class is documented and specifically designed to be sub-classed.
3.       Add forwarding methods to expose the methods of the contained class with or without custom logic depending on requirement
Design and document for inheritance or prohibit it

If a class is expected to be a super class then document its methods properly otherwise prohibit inheritance by defining it as final.

Some rules to follow when creating sub-classable classes

1.       Constructors must not invoke overridable methods, directly or indirectly.
2.       Avoid implementing Serializable and Cloneable in a overridable class. If implemented neither clone or readObject may invoke an overridable method directly or indirectly.
3.       Make the readResolve or writeReplace methods protected instead of private so that they can be extended by the subclass if required.

Prefer Interfaces to Abstract Classes

Extending abstract class will have the same limitations as inheritance. As opposed to Abstract classes interfaces provide a lot of flexibility and abilities.

Advantages

1.       Existing classes can be easily retrofitted to implement a new interface
2.       Allow for nonhierarchical type framework
3.       Ideal for defining mixin. (A mixin is a type that allows a class to exhibit extra behavior in addition to its “primary type”. E.g. a class that implements Comparable states that it can be ordered).
4.       Interfaces enable safe, powerful functionality enhancements.
5.       It promotes loose coupling between modules.

Disadvantages

1.       The one disadvantage Interfaces have against the Abstract classes is that one can evolve abstract classes by adding concrete methods to the abstract class as and when required. This is not possible with interfaces as all the classes that implement the interface will now need to implement this method.
Use Interfaces only to define types

In short do not define an interfaces with no methods. Do not use interfaces which only define constants. It is confusing to have an Interface which does nothing.
Favour static member classes over nonstatic

A class defined within another class is a nested class. One can have one of the following types of nested  classes:
1.       static member classes
2.       nonstatic member classes
3.       anonymous classes
4.       local classes.
A static member class has access to all the members of the class in which it is declared including the private members.
Syntactically a non-static is same as the static class except for the absence of the static keyword. Every instance of a non-static class can refer to the instance of the enclosing class using the qualified this. One classic use-case of usage of non-static member class is Iterators in the Collection and Map classes.
If a member class does not require access to the enclosing instance then put the static modifier.
Anonymous classes are classes without name which are used for a particular call. Comparator is a good use-case where an anonymous class is created and passed as the comparator object to be used for sorting.
Local classes can be declared anywhere, where a local variable may be declared and they follow the same scope as a local variable. They have the characteristics of a non-static inner class and have access to the enclosing instance.

In the next post we will read about the best practices of converting C structures to Java.

This is the second in the series of posts based on the book Effective Java by Joshua Bloch. The first post was about creating and destroying objects efficiently and effectively.
In this post we will see how to write correctly some of the the standard methods that can be implemented by every object.

Obey the general contract when overriding equals

The easiest option is not to implement equals method if it is not required. Under the following conditions do not implement the equalsmethod
1.       Each instance of the class is inherently unique
2.       You don’t create whether the class provides a “logically equality” test
3.       A super class has already overridden equals, and the behavior inherited is appropriate.
4.       The class is private or package-private and you are certain that its equals method will never be invoked.

Rules to adhere to

Override equals method if and only if you know that equals will be invoked implicitly or explicitly on the class and the default implementation will not be sufficient. Note that equals can be implicitly invoked if you look for List.contains or Map.containsKey or Map.containsValue or use it as a key in a Map or added to a Set.
If equals method is implemented it should satisfy the following conditions:
1.                   It should be reflexive: x.equals(x)must be true.
2.                   It should be symmetric: If x.equals(y)is true then y.equals(x) should also be true and vice-versa
3.                   It should be transitive: If x.equals(y)and y.equals(z)are true then x.equals(z) must also be true.
4.                   It is consistent: Multiple invocations of x.equals(y) should return the same result as long no information used in equals is modified.
5.                   For any non-null x, x.equals(null)should return false

Recipe for writing equalsmethod

1.       Use the == operator to check if argument is a reference to this object and if so return true.
2.       Use the instanceof operator to check if argument is an instance of the current class and if not return false. Note that this also handles the situation where the argument is null as a null object when checked against instanceof any other object returns a false.
3.       Cast the argument to the correct type.
4.       For each “significant” field in the class, check to see if that field of the argument matches the corresponding field of this object. If all such fields match then return true else return false.
a.       To compare any primitive value other than float and double use the == operator
b.      To compare float use float.floatToIntBits on both the values and use the == operator
c.       To compare double use double.doublToLongBits on both the values and use the == operator
d.      To compare any object use the equals method. Take care to handle null objects. Use this technique to compare object (field == o.field) || (field != null && field.equals(o.field))
5.       Override hashCode method if equals method is overridden.
6.       Do not substitute another type for Object in the equals declaration.
The signature of the equals method is
public boolean equals(Object o) {
}
Not
public boolean equals(MyClass o) {
}
7.       For performance structure the method such that the attributes that are most likely to change are compared before the attributes that are unlikely to change.
Always override hashCodewhen you override equals

One must override hashCode method in every class that overrides equals. If this is not adhered to then the class will not function as per expectations when used in any hash-based collections including HashMap, HashSet and HashTable.

Rules

1.       When hashCode is invoked on the same instance of object more than once, the value returned must consistently be the same integer as long as no information used in equals comparison is modified.
2.       If two objects are equal as per the equals method then the hashCode of both the objects must return the same hashCode.
3.       It is not required that the hashcode values returned by two objects which are not equal as per equals method then be different. But the system can give a better performance if this is adhered to.

Recipe for writing hashCode method

1.       Store some non-zero value say 17 in an int variable say result
2.       For each significant field f in the object do the following:
a.       Compute an int hash code c for the field
                                                   i.      If field is boolean compute (f ? 0 : 1)
                                                 ii.      If field is byte, char, short or int, compute int(f)
                                                iii.      If field is a long, compute (int) (f ^ f >>> 32)
                                               iv.      If field is a float, compute Float.floatToIntBits(f)
                                                 v.      If field is double, compute Double.doubleToLongBits(f) and then has the resulting long as in step iii.
                                               vi.      If the field is a class field and is used for comparison then invoke the hashCode for the object. If object is null use zero. Hashcode must be recursively invoked till objects have no more children
                                              vii.      If the field is an array, then treat as if each element were a separate field.
b.      Combine the hash code c into the result as follows:
                                                   i.      result = 37 * result + c
3.       Return result
4.       Consider caching the hashCode if there is a significant cost in computing this value. But be careful to recompute it if something changes.
5.       Do not be tempted to exclude significant parts of an object from the hash code to improve performance. This will lead to clashes in Hash Maps which will result in worse performance.
Always override toString

The default implementation of toString returns the name of the object and the hashCode which will not make sense. If a good toStringmethod is implemented then one would be able to understand what the object contains making debugging the system easier. toString should include values of all significant fields.
The general contract for toString says that the returned string should be “a concise but information representation that is easy for a person to read”.
It is advisable to document the format of the output that will be generated by the toString method.
All data that is exposed through toString should be available by their corresponding getter methods. If this is not the case then programmers will try to parse the string returned by toString and get the value which is a bad idea.
Override clone judiciously

Clone is like a constructor. The clone method should satisfy the following conditions:
1.       Implement the interface cloneable
2.       Although cloneable does not demand implementation of a clone method it is wise to provide an implementation except for trivial classes which deal with only primitive types.
3.       Consider satisfying the following rules:
a.       x.clone() != x. But this is not necessary.
b.      x.clone.getClass() == x.getClass().But this is not necessary.
c.       x.clone().equals(x). But this is not necessary.
4.       Return the object obtained by super.clone. Do not use constructor
5.       The original object should not be harmed by virtue of being cloned
6.       If required remove the final modifier of certain attributes to get a proper clone
7.       In case of Collections and Maps ensure that every object on the Collection or Map is cloned properly otherwise it will be a shallow copy and this can result in bugs.
8.       Cloneable final classes should not throw CloneNotSupportException from the clone method. This makes it easier to use the class.
9.       Classes that are extendable should implement an empty clone which throws CloneNotSupportException. This will ensure that the subclasses can by default opt out of cloning.
10.   Instead of clone method consider creating a copy Constructor or a static copy method.
public class MyClass {
    public MyClass(MyClass objectToCopyFrom) {
        //Logic to copy the incoming object.
    }
   //or
   public static MyClass getNewInstance(MyClass objectToCopyFrom) {
        //Instantiate new object copy the incoming object.
   }
}

Consider implementing Comparable

Implementing the Comparable interface helps one to leverage several generic algorithms and collection implementations that depend on this interface. sort method in the collections Collection objects like TreeSetetc. can be used.
The compareTo method should return a zero, negative or a positive integer depending on if the object is equal, less than or greater than the current object. If the object types prevent them from being compared it should throw ClassCastException.
The following rules should be followed:
1.       signOf(x.compareTo(y)) == – signOg(y.compareTo(x))
2.       x.compareTo(y) should throw an exception only if y.compareTo(x) also throws an Exception.
3.       It should be transitive. I.e. x.compareTo(y) > 0 and y.compareTo(z) > 0 then x.compareTo(z) > 0
4.       x.compareTo(y) == 0 should imply that signOf(x.compareTo(z)) == signOf(y.compareTo(z)) for all z.
5.       Ideally (x.compareTo(y) == 0) == (x.equals(y)). I.e. if compareTo indicates that the objects are equal then equals should also return true. If this is not true then this should be properly documented.

The next post is about the best practices in writing classes and interfaces.

This will be a series of posts based on the book Effective Java by Joshua Bloch. The posts will be split into the following parts based on the chapters in the book.

  1. Creating and Destroying Objects
  2. Methods Common to All Objects
  3. Classes and Interfaces
  4. Substitutes for C Constructs
  5. Methods
  6. General Programming
  7. Exceptions
  8. Threads
  9. Serialization

This post will cover Creating and Destroying Objects

Providing static factory method

Consider providing static factory methods in the object to create instances of the class.

Benefits

1.       Methods can be named to indicate the type of object that is being returned. This will avoid the problem where it is found necessary to have two constructors having the same signatures, but different parameters.
2.       Factory methods do not need to construct an instance each time they are invoked. This can be useful in limiting the number of object instances of a class created in the JVM. This can be used to create immutable classes. E.g. factory methods the Boolean class can be used to ensure that only two objects of type Boolean ever exist in the JVM. Additional advantage is if a == b also means a.equalsEvery method expects a (b) and the performance of == can be significantly better than ==.
3.       Factory methods need to return the same class, but can return any object which is a subtype of the return type.  This can be used to hide classes in libraries. Only the interface will be exposed to the outside world.

Disadvantages

  1. 1.       Classes without public or protected constructors cannot be subclassed.
  2. 2.       The methods used to create instances of class are not distinguishable from other methods of the class. It can be difficult to identify such methods easily in a class.

Examples

The collections class java.util.Collections can be used to instantiate a variety of Collection classes. The Java Cryptographic Extension uses this method to allow instantiation of the multiple implementation of the APIs.
Enforce Singleton Pattern with a private Constructor

A singleton is a class which has only one instance in the JVM.
There are two ways to create a Singleton
public class FirstSingleton {
    public static final FirstSingleton INSTANCE = new FirstSingleton();
    private FirstSingleton () {
    }
}
public class SecondSingleton {
    private static final SecondSingleton INSTANCE = new SecondSingleton ();
    private SecondSingleton () {
    }
    public static SecondSingleton getInstance() {
        return INSTANCE;
    }
}
The advantage of the second method is that if in a future date one wishes to convert the object from a Singleton to Multiton it will be possible without changing any references to this object. This will be near impossible if one adopts the first pattern.
If we wish to make a Singleton class Serializable then just implementing the interface will not be sufficient, one will need to implement the readResolve method too so that multiple instances of the class are not created.
Enforce noninstantiability with a private constructor

Sometimes there is a requirement for a class which has only static methods and constants. Typically utility classes will fall under this category.
For such classes one should define a private constructor so that this can never be instantiated. If this private constructor is not defined then it will be possible to instantiate this class which does not make sense.
This will also prevent the class from being subclassed.

Examples

1.       java.util.Arrays
2.       java.util.Math
3.       java.util.Collections

Avoid creating duplicate objects

When objects are immutable it makes sense to use the same instance of the object rather than creating a new instance.
E.g.
String s = new String(“silly”); //Don’t do this.
This unnecessarily creates another instance of the String whereas the following would have sufficed.
String s = “silly”;
Any object that needs to contain a constant value should be defined once and reused instead of being instantiated again and again. E.g. fixed dates against which some other dates must be compared.
Note: Creating objects is not very expensive but they should be created only when required or when it makes sense to create objects to keep the code simple and clear.
Maintaining an object pool is a bad idea unless the objects are real heavy weights, i.e. creation of these objects are expensive. One example of such an object is the Database Connection.
Be careful and do not reuse an object which should not be. Typically objects that can change should not be reused, instead a new instance or a copy should be made.

Eliminate obsolete object references             

Objects that are no longer required, but may not be Garbage Collected by virtue of it going out of scope should be nulled so that they can be garbage collected.
Consider the following example which is an implementation of Stack:
public class Stack {
    private Object[] elements;
    private int size = 0;
    public Stack (int initialCapacity) {
        this.elements = new Object[initialCapacity];
    }
    public void push (Object e) {
        ensureCapacity();
        elements[size++] = e;
    }
    public void Object pop() {
        if (size == 0) throw new EmptyStackException();
        return elements[–size];
    }
    /**
     * Ensure space for at least one more element, roughly
     * doubling capacity each time the array needs to grow.
     */
    private void ensureCapacity() {
        if (elements.length == size) {
            Object[] oldElements = elements;
            Elements = new Object[2 * elements.length + 1];
            System.arrayCopy(oldElement, 0, elements, 0, size);
        }
    }
}
On the face of it the object is fine and there are no problems, but there is a hidden memory leak. This happens in the pop method. As the objects are popped out of the stack they are no longer required in the array, but since there is a reference to these objects in the array the garbage collector does not know that these can be collected. This means that even though the Stack has shrunk in size the memory is not getting released and this can cause problems depending on how the object is used.
The way to fix is to nullify the references that are not required as below
    public void Object pop() {
        if (size == 0) throw new EmptyStackException();
        Object result = elements[size];
        elements[–size] = null;
        return result;
    }
This does not mean that one should nullify every object that is not required. This mechanism should be used only under condition as described above, i.e. in scenarios where the Class is managing its own memory without the knowledge of Garbage Collector.
Cache is another source of such leaks. If object in the cache are no longer required, then references to them should be removed. If the reference to the objects needs to cease based on reference to the object outside the scope of the cache then using a WeakHashMap will automatically remove the object from the Map once the reference to the object outside the cache is removed.
If it is not known as to when the object out of scope but it is desired that it be possible to remove objects based on the oldest object then we can use the LinkedHashMap object. This allows for removeEldestEntry which will remove the earliest entry.
Avoid Finalizers

Finalizers are invoked when the object is Garbage collected. It is not known as to when the Garbage Collection will kick off. Given this one should not depend on the finalzer to free resources. Resources should be freed typically in the finally block. If one depends on finalizer to free resources it maybe too late. Expect the clients of the class to invoke the method for freeing of the resources 

The next post is about the best practices in writing methods which are common to all the classes.


Categories

Advertisements