Skip to content
Front page » TechNexus – Blog » Common Java Pitfalls Cookbook

Common Java Pitfalls Cookbook

trampas comunes en Java

Common Java Pitfalls Cookbook

This document compiles common errors and subtle behaviors in Java that can lead to hard-to-detect bugs. Each entry follows the outline problem → solution → discussion so you can identify, understand, and avoid these errors in your code.


1. Integer comparison outside the cached range

Problem: The operator == returns false for integers greater than 127 (or less than -128) even if the numerical values are equal.

Solution: Use .equals() to compare values of Integer. For performance or simplicity, use int if you don't need nulls.

Discussion: Java caches the Integer in the range [-128, 127]. Outside that range, Integer.valueOf() returns distinct instances; == compare references, not content.


2. Comparing String with ==

Problem: == between chains sometimes it gives true and others false for the same text, which confuses beginners.

Solution: Compare strings with .equals() either .equalsIgnoreCase().

Discussion: He string pool You can make two literals point to the same reference, but objects created with new String() No. == compare references; .equals() compare content.


3. Modify a collection during iteration

Problem: Remove or add items to a collection while browsing with for-each lance ConcurrentModificationException.

Solution: Use a Iterator and his remove(), or collect first and modify later; alternatively, use concurrent collections.

Discussion: Many collections detect structural changes during iteration. Concurrent collections (e.g., CopyOnWriteArrayList) have different semantics and additional costs.


4. NullPointerException when unboxing

Problem: Convert a Integer null to int produces NullPointerException.

Solution: Valid null before unboxing or use OptionalInt / default values.

Discussion: Unboxing internally invokes intValue() about the reference; if it is null, fails. Avoid this wherever possible by using primitive types.


5. Arrays do not deep copy

Problem: Assigning an array to another variable copies the reference; changes in one view affect the other.

Solution: Use Arrays.copyOf() either clone() to copy the array; for arrays/objects, implements an explicit deep copy.

Discussion: Copying by reference is fast but surprising for those who expect data independence. For nested structures, it copies each level.


6. Lack of break in switch (fall-through)

Problem: Forget break runs additional cases unexpectedly.

Solution: Duck break or use switch with expressions (Java 14+) and ->, which does not do fall-through default.

Discussion: He fall-through It is useful in grouped cases, but it is often a source of bugs. Expressions switch modern technologies reduce this risk.


7. Virtual calls in constructors (incomplete initialization)

Problem: Calling overridden methods from a constructor may use uninitialized fields of the subclass.

Solution: Do not invoke overridden methods in constructors; use methods end or explicit initialization.

Discussion: The superclass constructor executes before initializing the subclass fields. The virtual call accesses an incomplete state.


8. Arrays of generic types

Problem: Arrays of specific generic types cannot be created, e.g., new ArrayList [10].

Solution: Use List [] or preferably collections, avoiding generic arrays.

Discussion: Arrays are covariant and reified; generics use type erasure. Mixing breaks type safety at runtime.


9. Mutable keys in HashMap/HashSet

Problem: Changing a key after entering it prevents it from being found again.

Solution: Use immutable keys (e.g., record or immutable classes) or do not modify the keys after using them.

Discussion: hashCode() and equals() determine the location. If they change, the map loses its reference to the entry.


10. Optional.get() without checking presence

Problem: Call to get() about a Optional empty spear NoSuchElementException.

Solution: Use orElse(), orElseGet(), orElseThrow() either ifPresent().

Discussion: Optional aims to avoid null; wear get() breaks its intent. Prefers expressive APIs.


11. Variable shadowing (field hiding)

Problem: The method parameter hides the instance field and assignments like name = name; They do nothing useful.

Solution: Use this.name = name; or change the parameter name.

Discussion: Shadowing hampers maintenance and causes silent bugs. Enabling IDE inspections helps detect it.


12. Attendance: lack of volatile (visibility)

Problem: A thread does not observe changes by another thread to a variable without synchronization.

Solution: Declare the variable as volatile or synchronize accesses (synchronized, Lock).

Discussion: The Java memory model allows for per-thread reordering and caching. volatile guarantees visibility and order of publication/reading.


13. Concurrency: Non-atomic increments

Problem: Operations such as value++ lose updates under concurrency.

Solution: Use AtomicInteger.incrementAndGet(), blocks synchronized or accumulators (LongAdder).

Discussion: value++ implies read-modify-write. Without mutual exclusion, two threads can overwrite results.


14. Calendar: zero-based month

Problem: Calendar#set(year, month, day) interprets January as 0; 10 It's November, not October.

Solution: Use constants (Calendar.OCTOBER) or migrates to java.time.

Discussion: The old date API is prone to errors. java.time (JSR-310) is clearer and more immutable.


15. LocalDate.parse() with non-ISO formats

Problem: LocalDate.parse("05/10/2025") lance DateTimeParseException.

Solution: Define a formatter: DateTimeFormatter.ofPattern("dd/MM/yyyy") and pass it to parse().

Discussion: Default, parse() wait yyyy-MM-ddFor other formats you must specify the pattern explicitly.

en_USEnglish