Top Mistakes of Beginner Java Developers: Advanced Level
Many developers, having mastered the basics of Java, move on to writing more complex code but continue to make typical mistakes that reduce application performance and reliability. In this article, we will analyze the top mistakes at an advanced level that Java developers encounter and show how to avoid them. The article will be useful for those who are already familiar with the language syntax but want to deepen their knowledge.
1. Incorrect Use of Optional
The Optional class was introduced in Java 8 to combat NullPointerException. However, many developers use it incorrectly, turning an elegant solution into a source of new problems.
Mistake: Using Optional.get() Without Checking
One of the most common mistakes is calling the get() method without first checking isPresent(). This leads to a NoSuchElementException.
// IncorrectOptional<String> name = Optional.ofNullable(getName());String result = name.get(); // Exception if name == null
// CorrectString result = name.orElse("Default");// Or with handlingname.ifPresent(System.out::println);Mistake: Using Optional in Class Fields
Optional is not intended for use as class fields or method parameters. This breaks serialization and adds unnecessary complexity.
// Incorrectpublic class User { private Optional<String> email; // Not serializable}
// Correctpublic class User { private String email; // null means absence}Mistake: Chaining Optional.orElse() with Expensive Computations
The orElse() method always evaluates its argument, even if the value is present. Use orElseGet() for lazy evaluation.
// Incorrect — expensiveCall() is always executedString result = optional.orElse(expensiveCall());
// Correct — expensiveCall() is executed only when value is absentString result = optional.orElseGet(() -> expensiveCall());2. Memory Leaks and Incorrect Work with Collections
Advanced developers often encounter memory leaks that are difficult to detect. Let's look at the main causes.
Mistake: Forgetting to Override equals() and hashCode()
When using objects in HashMap or HashSet without correct equals() and hashCode(), objects are not removed from the collection, leading to leaks.
public class Key { private int id; // Forgot to override equals() and hashCode() // Now keys are considered different, even if id matches}
Map<Key, String> map = new HashMap<>();map.put(new Key(1), "value");map.get(new Key(1)); // null — memory leakMistake: Storing Large Objects in Static Collections
Static collections live until the application ends. If data is added to them without control, this will lead to OutOfMemoryError.
// Bad practicepublic class CacheManager { private static List<byte[]> cache = new ArrayList<>(); public static void addData(byte[] data) { cache.add(data); // Grows indefinitely }}
// Solution: use WeakHashMap or limit the sizeprivate static Map<String, byte[]> cache = new WeakHashMap<>();Mistake: Closing Resources via finalize()
The finalize() method is deprecated and unreliable. Use try-with-resources for automatic closing.
// Incorrectpublic class Resource { @Override protected void finalize() throws Throwable { // Closing resource — may not be called