posts
Repetitive mistakes in Java code

Repetitive mistakes in Java code

Aug 24, 2023
Tagir Valeev
7.5

It’s no secret that programmers make mistakes in the code: after all, to err is human. But errors cost time and money. If an application works incorrectly due to bugs, it takes time to reproduce the problem, nail down the mistake, fix it, and redeploy the application. The amount of support requests increases, and customer satisfaction goes down. The developers feel annoyed and depressed when they see that the program doesn’t work as expected. So avoiding mistakes or discovering them as early as possible is natural.

Common caveats

There are different kinds of mistakes. Some are complex and unique and happen once in a lifetime. On the other hand, many mistakes are repetitive, and developers stumble on them again and again.

Here’s a simple example. Imagine that you have a method that accepts a numeric parameter, and you want to perform a range check before further processing. For instance, your method accepts a percentage of progress and updates a progress bar in the user interface. It may look like this:

void updateProgress(double percent) {
if (percent < 0.0 && percent > 100.0) {
throw new IllegalArgumentException("Invalid value: " + percent);
}
// ... actual UI update logic goes here ...
}

Do you see the problem? Here, && operator was used instead of ||. As a result, the range check doesn’t do anything because no number can be less than zero and greater than 100 simultaneously. When I show this sample to developers, some say: “Oh, come on! No professional developer would make such a stupid mistake!” Yet, I’ve seen dozens of times when && was mistakenly used instead of ||, or vice versa. These errors were found in production codebases maintained by professional developers. Spotting such a mistake in a short code snippet is not difficult, but when you write or review hundreds of lines of code, it’s easy to use the wrong operator without even noticing.

Ways to avoid repetitive mistakes

What can developers do to avoid such mistakes? Well, this particular problem is caught by IntelliJ IDEA’s built-in static analyzer. If you use it to write the code, you should not set up anything; it will work out of the box. Don’t ignore the highlighting, and pay attention to what IDE says to you:

Highlighting the problematic code in IntelliJ IDEA

However, static analysis is limited. It knows a little bit about numbers, but it knows less about strings. For example, consider you are writing another method that needs to process lines, skipping comment lines, which start either with ‘#’ or with ‘//.’ You may write something similar to:

void processLine(String line) {
if (line.startsWith("#") && line.startsWith("//")) {
// comment line: skip it
return;
}
// ... process non-comment line ...
}

The same mistake is made here: && is used instead of ||, so no lines will be skipped. But now, the built-in static analyzer in IntelliJ IDEA doesn’t help you: it’s not smart enough to reason that no line can start with ‘#’ and with ‘//’ at the same time.

You can try out bleeding-edge technology such as the AI Assistant, which uses a large language model like ChatGPT under the hood. Currently, it’s provided as an IntelliJ IDEA plugin. After installing it, you may invoke “AI Actions → Find potential problems” from the context actions menu when staying on the method declaration. For this particular code sample, it does its job pretty well:

IntelliJ IDEA AI Assistant plugin at work

It found the problem, explained it, and suggested how to fix the code. Looks great! However, you cannot feed every single piece of your code you write to the AI assistant and check its output. The programming process will become unbearably slow. Also, if you ask the AI assistant to find the problems in the correct code, it tries to find at least something, even if it’s not a real problem. So you’ll have to read all the AI assistant’s output to understand which issues are actual and which are just nitpicking. This may take more effort than just rereading your code and trying to find the problems yourself.

The best solution is to be on full alert

In my opinion, the best solution is to be prepared. As a programmer, you should know in advance the possible caveats. For instance, whenever you use && or ||, you should automatically consider whether the operator is correct. You can check a couple of input values in your head and see whether the result of the condition is appropriate. Or you can write a couple of unit tests to ensure the condition works as expected. There are not always enough resources to cover every bit of your code with a unit test, so it’s good to know where errors are more likely to hide and which code constructs are more critical to test.

A while ago, I started to record and categorize repetitive Java mistakes and ways to avoid them. Eventually, this turned into a book, which is almost finished now. The book is called “100 Java Mistakes and How to Avoid Them.” The part of it is already available on the Manning publisher website. Although the book targets middle-level Java developers, it could interest juniors and advanced students. On the other hand, more experienced programmers may also learn something new from it.

For BellSoft blog readers, a permanent discount code is available: bellsoft35. Use it to get the book with a 35 % discount unless there’s an ongoing sale, which provides an even better deal.

Subcribe to our newsletter

figure

Read the industry news, receive solutions to your problems, and find the ways to save money.

Further reading