How to Avoid Common Java Bugs


Good Programming Practices -

How to Avoid Common Java Bugs


We developers always want to write clean, bug-free and elegant code. This need practices.

We all know that except trivial ones, no program is bug-free, but some skills and practices can help us to prevent some common mistakes we may make.
Understanding is everything.
Learn and understand the function requirement before start to write code or fix bugs.
Don't copy and paste, instead factor out common code.
Make full use of tools to check your code.
There are many wonderful tools that can help us to check our code to avoid most of common mistakes. They also integrate well with IDE, such as Find Bugs, PMD, Google CodePro AnalytiX.
These tools always provide good explanation what's wrong and how to fix it. This can save us a lot of time.
Review your code again before writing tests, Review your code again before checking in your code.
l          Check Javadoc and specification and ensure the method/class does what is required, and no more things.
Write Unit tests to find bugs and guarantee code quality.
Always refactor your code.
Follow programming idiom.
Rely only on documented behavior, don't make assumption.
l          When call third-party API, use it as the Javadoc says, don't make assumption, and don't delve into its code, and rely on the implementation, as the implementation may change in future version.
If the Javadoc isn't clear, contact the developer if possible to make it clear and fix it.
l          When call third-party API, don't make assumption it is 100% correct and bug free. Write tests to verify you method, and verify the third-party API works as we want.
The most Common Bugs
Off-by-one error
It often occurs when an iterative loop iterates one time too many or too few.
Check start and end condition of the loop. Normally the condition looks like m <= X m end ([m, n)). If not, check why, and fix it if possible.
Check whether the last value is processed in the loop. If not, maybe we need handle the last value after the loop.

Pay special attention to boolean value, loop initial value etc.
Whether the boolean value should be true or false. This often happens when we copy and paste code.
Don't return null, or pass null.
Returning null or an error value instead of throwing an exception to indicate an exceptional condition.
Failing to clone returned objects
We accidentally break encapsulation by returning references to private data. The fix is to return a deep clone object.
Forget to check parameter validity, preconditions and null pointers.
Also don't forget to document these preconditions in method comments.
Confusion over passing by value, and passing by reference.

Bug patterns
Avoid Copy-and-Paste
Symptoms: The code seems to act as if a previously corrected bug is still there.
Cause: At least one copy of a copy-and-paste code fragment still contains a bug fixed in the other copies.
Cures and Preventions: Factor out the common code, if possible; otherwise, update it. Avoid copying and pasting code.
The Null Flag
Symptoms: A code block that uses null pointers as flags for exceptional conditions signals a NullPointerException.
Cause: The calling methods are not checking for null pointers as return values.
Cures and Preventions: Don't return null, throw exceptions to signal exceptional conditions.
Saboteur Data
Perform as many integrity checks on input data as possible, as early as possible.
The Impostor Type
Symptoms: A program that treats data of conceptually distinct types in the same way, or that doesn't recognize certain types of data.
Cause: The program uses fields with tags in lieu of separate classes for the various types of data.
Cures and Preventions: Divide conceptually distinct types of data into separate classes whenever possible.
The Split Cleaner
Symptoms: A program that improperly manages resources, either by leaking them or by freeing them too early.
Cause: Some execution paths of the program do not free the resource exactly one time as they should.
Cures and Preventions: Move the code that handles clean up into the same method that obtains the resource.
The Fictitious Implementation
Pattern: Fictitious Implementation.
Symptoms: A client class that works with a specified interface breaks when a certain implementation of that interface is used.
Cause: The interface includes many intended invariants that aren't satisfied by the implementation.
Cures and Preventions: Fix the implementation to include those invariants. Make the invariants explicit in the documentation of the interface, if they aren't already.
The Orphaned Thread
Cause: Various program threads are stuck waiting for input from a thread that exited after an uncaught exception was thrown.
There are several dependent threads in programs. When one thread exits, normally or abnormally, it fails to notify the dependent threads, this would cause other threads stuck or other problems such as out of memory exceptions (if consumer threads dies, server thread would generate element for ever and OOM at last).
Cures and Preventions:
If the thread is meant to run forever then capture all exception in the thread to prevent its termination.
Notify the dependent threads when the thread terminates.
The Run-On Initialization - Incomplete Initialization
Symptoms: A NullPointerException at the point that one of the uninitialized fields is accessed.
Cause: A class whose constructors don't initialize all fields directly.
Cures and Preventions: Initialize all fields in a constructor. Use special classes for default values when better values can't be used. Include multiple constructors to cover cases where better values can be used.
Initialize the fields to non-null, default values.

Miscs
Failing to implement equals, hashCode, or clone correctly.
l          When extending a class that overrides one or more of these methods, the child class usually needs to override the methods, too. Code reviews should check to ensure that if parent classes implement, the child classes are still correct.
Using == instead of .equals
Overriding equals() and not hashcode(), and vice versa.
Switch case without break
Writing blank exception handlers
Forget to implement Serializable interface.
Failing to synchronize getters which access mutable data in classes which need to be thread-safe.
Using magic numbers where enums would be better.
Closing streams and connections at the end of the try block and not in the finally block.
Java Anti-Patterns
Infinite heap
Infinite time
The transient trap
l          Never use transient variables in constructor.
Having a global Configuration/Parameters/Constants class
Not noticing overflows
Using == with float or double
Assuming SimpleDateFormat was thread-safe
Undefined encoding
Unbuffered streams
Incomplete exception handling
Abusing finalize()

Resources:
Bug Patterns In Java
Java Anti-Patterns
Common programming mistakes for Java developers to avoid?
Common Java Mistakes and Bug Patterns

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)