7 Java Mistakes to Conquer
There’s no denying the necessity of clean code — code that is consistent, intentional, adaptable and responsible. Ask any developer and they’ll agree that it should be top of mind when creating a project. But code is only as good as its weakest link, and as seen in the telemetry data from SonarLint, there are still plenty of issues that appear in the giant list of analyzed projects.
Even though some of the problems can look trivial, they can have a significant impact on software when it comes to security, performance and maintenance. That’s why I’ve compiled a list of the most common errors we find in Java projects, from the more than 600 rules covering the language, taking quality and security into consideration. With these in mind, you can better set yourself up to create code that is continuously consistent, intentional, adaptable and responsible — all at a huge benefit and low level of effort.
1. Code Commented Out
Code commented out only presents a challenge to its readability, so it should be removed for clarity. This eliminates uncertainty for the reader, as it can be difficult to ascertain whether the code was commented out temporarily or should have just been removed. A helpful hint to follow for this: If it doesn’t apply to the submitted feature, take it out or uncomment it if it is a temporary disabling.
Here’s an example:
The good news is that if you later need the commented code, you can simply retrieve it from the version control system.
2. Neglected ‘TODO’ Tags
Leaving these comments in the source code, which will likely have a long lifespan, leads to incomplete code that can affect software on several fronts. For instance, when it comes to collaboration within a team, some members may not know which features will be included in the final release. These tags can also give the appearance of being able to be handled later, rather than implementing those parts now and reducing the chance of future bugs. Additionally, TODO blocks can lead to leaky performance in the future.
Here’s a real-life example of a project called Apache Camel with a TODO line introduced almost a decade ago.
To avoid these issues, don’t add new TODO blocks. Instead, implement the feature before submitting the final code — or record these tasks into the task manager so it’s clear how to tackle them in the future.
3. Duplicated String Literals
Duplicated strings lead to extra work or missing changes when those values must be changed to adjust to new conditions. Instead, use constants to store string literals. This makes refactoring easier and improves the consistency of the codebase.
An example of how to do this:
4. High Cognitive Complexity of Functions
More commonly, we hear about cyclomatic complexity, which measures how many paths are used in the code and helps determine the reading complexity for a given part of the code. But this concept can’t help figure out the real maintainability level that needs more considerations than just the number of conditionals or loops.
Reducing the code complexity is a critical piece in making refactoring, fixes and evolutions easier, as developers spend a lot more time reading code than they do writing it. Projects can often be hard to read or understand, and this issue makes it hard to know its intention and tackle both its maintenance and evolution. Developers should invest in refactoring code with a high level of cognitive complexity so the codebase becomes easier to understand and maintain in the long run.
With new code, it’s good to reference the complexity index and invest time in reducing it to the configured threshold that should be low enough.
5. Unused Elements
It’s easy for developers, as they code a new feature, to create elements of the code that eventually don’t have a purpose. These elements don’t cause runtime errors or failing tests, so they can be tricky to identify even though they need to be removed. But in the worst case, they can force us to rethink the code entirely.
These unused elements reduce the code’s readability, which makes it even harder to pinpoint the intention of the code and can cause a lack of confidence in its completion. Take them out. Check the unused code and remove whatever is no longer useful, or consider if they’re missing code that may use those elements. Take a look:
6. Raw Types
In Java, don’t use generic types without type parameters — it’ll avoid type checking and catching unsafe code during compilation, which makes everything visible during runtime. Instead, use specific types that allow users of those variables to understand what’s really expected and will eliminate surprises during that runtime. See below:
7. Thrown Generic Exceptions
Using generic exceptions prevents the calling methods from handling different system-generated exceptions and application-generated errors. To avoid this, create a custom system of exceptions that provides enough information to the caller so they can decide what to do, fully equipped with a detailed and differentiated list of caches.
Avoiding Mistakes Leads to Better Software
All developers go into coding with the intention of creating a final product that’s high quality, reliable, adaptable and secure. But it’s easy for these seemingly small, everyday mistakes to get in the way of that goal. Taking note of these issues moving forward and doing your best to avoid them will only set you up for the kind of clean code software that allows a business to thrive.