When working with strings inside a loop, it is important to use the StringBuilder class instead of concatenating them with the + operator. StringBuilder is more efficient, as it doesn't create a new string each time you concatenate, which can lead to memory issues if the strings are large or if you're concatenating many strings together.
As an example, consider the following code:
StringBuilder sb = new StringBuilder();
String letters = “”;
for (int i = 0; i < 1000; i++) {
sb.append("a");
letters += “a”;
}
String s = sb.toString();Though you should use a StringBuilder in a loop, concatenation with a + is no different outside a loop. This is because the Java compiler will automatically optimize the code and use a StringBuilder instead.
Null pointer exceptions are runtime errors, meaning the compiler won't alert you to them. Because of this, you may need robust testing to prevent them from causing your code to crash. That’s why a reviewer needs to consider returned values when methods are called and variables are accessed.
If a variable is expected to be null, then a null check should be done before accessing it. Suggest Objects.requireNonNull(), Optional, or using @NotNull annotations. This operator will check whether a given reference is null before accessing it. If it is null, then it will return null instead of throwing an exception.
Here’s an example of null checking with an if condition:
if (obj != null) {
obj.doSomething()
}While this is what the same code looks like with the safe navigation operator:
obj?.doSomething()You can suggest using the safe navigation operator in place of explicit if checks if doing so will make the code easier to read and require fewer lines.
Understanding the code you’re reading is important for providing valuable feedback about valid null checks. If some code depends on an external service, you must understand the possible values returned and consider the failure modes.
While null checks are important, you should make sure they aren’t used unnecessarily, as this can be confusing for a reader or even hide bugs if a null value should never occur.
One of the key features of object-oriented programming is polymorphism — the ability for an object to take on multiple forms. For example, a shape can be a circle, square, or triangle. Each has its own properties, but all can be referred to as shapes.
Polymorphism can often replace long chains of if or switch statements. If you see code with many conditionals that check an object’s type, that’s usually a sign polymorphism would be a cleaner solution.
As an example, consider the following code:
if (shape instanceof Square) {
// do something
} else if (shape instanceof Circle) {
// do something
} else if (shape instanceof Triangle) {
// do something
}
This can be rewritten using polymorphism as follows:
shape.draw();When reviewing code like this, you could suggest how polymorphism can reduce the need to use conditionals in multiple places.
Memory leaks happen when objects are no longer being used but are still referenced by the program. This means they can't be garbage collected and will stay in memory until the program exits, which can lead to OutOfMemoryError exceptions being thrown or performance degradation that is hard to debug.
Java’s garbage collector usually handles memory cleanup automatically, but leaks can still occur in some cases.
Make sure that resources are closed after using them, as in the example below. This is especially important when working with files, databases, and network connections.
FileInputStream fis = new FileInputStream("file.txt");
// do something with the file
fis.close();Another way you may get a memory leak is by overusing static variables. These variables are initialized when the class is loaded and stay in memory until the program exits. If these variables hold onto references, a memory leak may result.
Suppose you had a class named Session that kept track of all the users who join a given session:
class Session {
static User[] users;
}The user array will stay in memory for the entire lifetime of the program. As the array grows you may run into memory issues.