6 Common Java Pitfalls Every Developer Should Avoid
This article highlights six frequent Java pitfalls—including misuse of == with Integer, Objects.equals quirks, BigDecimal precision loss, Stream filter side‑effects, auto‑unboxing null errors, and String replace nuances—providing code examples and best‑practice recommendations to help developers write safer, more reliable code.
1. Using == with Integer
Comparing two Integer objects with == often yields false because the new Integer() constructor creates distinct objects that are not cached. The correct way is to use equals() or Integer.valueOf() which leverages the -128 to 127 cache.
Integer orderStatus1 = new Integer(1);
Integer orderStatus2 = new Integer(1);
System.out.println(orderStatus1 == orderStatus2); // false
System.out.println(orderStatus1.equals(orderStatus2)); // true2. Objects.equals Pitfall
When checking a user’s ID against a constant (e.g., 888L), using Objects.equals(userInfo.getId(), 888L) can fail because the Integer wrapper does not equal a Long. Ensure both sides are the same type or compare primitive values.
UserInfo userInfo = CurrentUser.getUserInfo();
if (Objects.isNull(userInfo)) return;
if (Objects.equals(userInfo.getId(), 888L)) {
sendEmail(userInfo);
}3. BigDecimal Precision Pitfall
Creating a BigDecimal with a double constructor can introduce hidden precision errors (e.g., new BigDecimal(0.02) yields 0.020000000000000000416...). Use BigDecimal.valueOf(double) or new BigDecimal(Double.toString(double)) to preserve exact values.
BigDecimal a = new BigDecimal(0.02); // inaccurate
BigDecimal b = BigDecimal.valueOf(0.02); // accurate
System.out.println(b.subtract(a));4. Java 8 Stream filter Pitfall
Filtering a list with stream().filter(...) returns a view that holds references to the original objects. Modifying an element in the filtered list also changes the original list because both lists share the same object instances.
List<User> filtered = users.stream()
.filter(u -> u.getId() > 1000 && u.getAge() > 18)
.collect(Collectors.toList());
for (User u : filtered) {
u.setName(u.getName() + "Test");
}
// original 'users' list now contains the modified names as well5. Auto‑unboxing Pitfall
Unboxing a
null Integerto a primitive int triggers a NullPointerException. Always check for null before arithmetic operations or use primitive parameters.
Integer a = new Integer(1);
Integer b = null;
System.out.println(add(a, b)); // throws NPE because of unboxing
private static int add(Integer a, Integer b) {
return a + b; // auto‑unboxing occurs here
}6. String replace Pitfall
The String.replace() method replaces all occurrences of a literal character or CharSequence without needing regex escaping, while replaceAll() treats the first argument as a regular expression. Using the wrong overload (e.g., escaping a literal * in replace()) results in no replacement.
String s = "A*B*";
System.out.println(s.replace("*", "C")); // ACB C
System.out.println(s.replaceAll("\\*", "C")); // ACB C (regex)
// Wrong usage:
System.out.println(s.replace("\\*", "C")); // unchangedUnderstanding these subtle behaviors helps avoid unexpected bugs in everyday Java development.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
