Avoid Common Java Pitfalls: Object Comparison, Ternary Unboxing, Generics & More

This article examines frequent Java development traps—including object comparison quirks, ternary‑operator unboxing, generic type mismatches, property‑copy issues, Set deduplication, and Spring CGLIB proxy pitfalls—provides bytecode‑level analysis, and offers practical coding guidelines and best‑practice solutions to prevent them.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
Avoid Common Java Pitfalls: Object Comparison, Ternary Unboxing, Generics & More

1. Object Comparison Method

Before JDK 1.7, comparing wrapper types with == works because the compiler automatically unboxes the wrapper to its primitive type. After JDK 1.7, using Objects.equals may give different results because it compares the objects themselves.

Problem Phenomenon

Short shortValue = (short)12345;
System.out.println(shortValue == 12345); // true
Integer intValue = 12345;
System.out.println(intValue == 12345); // true
Long longValue = 12345L;
System.out.println(longValue == 12345); // true

Using Objects.equals:

Short shortValue = (short)12345;
System.out.println(Objects.equals(shortValue, 12345)); // false
Integer intValue = 12345;
System.out.println(Objects.equals(intValue, 12345)); // true
Long longValue = 12345L;
System.out.println(Objects.equals(longValue, 12345)); // false

Analysis: the == operator triggers compiler‑generated bytecode that unboxes the wrapper to a primitive, while Objects.equals compares object types; mismatched types return false.

Avoidance

Declare constants with the exact primitive type, e.g. shortValue == (short)12345.

Enable IDE warnings for unlikely argument types (e.g., "Unlikely argument type for equals(): int seems unrelated to Short").

Write unit tests to catch such mismatches early.

2. Ternary Expression Unboxing

When a ternary operator mixes a primitive expression with a wrapper object, the compiler promotes the wrapper to its primitive type, which can cause a NullPointerException if the wrapper is null.

Problem Phenomenon

boolean condition = false;
Double value1 = 1.0D;
Double value2 = 2.0D;
Double value3 = null;
Double result = condition ? value1 * value2 : value3; // throws NPE

Bytecode shows that the false branch still invokes value3.doubleValue(), leading to the exception.

Avoidance

Replace the ternary with an explicit if‑else when dealing with wrapper types.

Prefer primitive types in the expression, e.g. use double instead of Double.

3. Generic Object Assignment

Assigning List<UserDO> to List<UserVO> compiles because of raw‑type compatibility, but it hides type‑safety problems and can lead to runtime errors.

Problem Phenomenon

return new PageDataVO(totalCount, dataList);

The generic parameters are not checked, so a List<UserDO> is assigned to a PageDataVO<UserVO> field.

Avoidance

Use diamond syntax: new PageDataVO<>(totalCount, dataList) to enforce type checking.

Enable compiler warnings for raw types and unchecked conversions.

4. Generic Property Copy

Using BeanUtils.copyProperties may fail when source and target property types differ (e.g., Object vs Long), because the utility checks assignability before copying.

Avoidance

Do not rely blindly on third‑party utilities; verify type compatibility manually.

For a small number of fields, write explicit copy code.

5. Set Object Deduplication

HashSet

removes duplicates based on hashCode and equals. If a custom class does not override these methods, logical duplicates are not eliminated.

Problem Phenomenon

Set<City> citySet = new HashSet<>();
citySet.add(new City("010","北京"));
citySet.add(new City("010","北京")); // not deduped

Avoidance

Override hashCode and equals in the element class, comparing the unique fields (e.g., code).

When uniqueness is guaranteed, use a List instead of a Set.

If duplicates are possible but need to be keyed, use a Map<String, City> keyed by the unique attribute.

6. Public Method Proxy

Spring CGLIB proxies only non‑final methods. If a method is declared final, the proxy does not intercept it, causing state inconsistencies between the original and proxy instances.

Avoidance

Do not mark beans or methods as final when they need to be proxied.

Limit proxy scope to only those beans that truly require AOP.

7. Public Field Proxy

Public fields are not initialized in CGLIB proxy subclasses, so accessing them through the proxy returns null.

Avoidance

Prefer private fields with public getter/setter methods.

Define immutable constants as public static final to avoid proxy interference.

Follow JavaBean conventions: no public instance variables.

In Java, the default type for integer literals is int , and for floating‑point literals is double .

Overall, the article promotes good coding habits, proper use of IDE warnings, thorough unit testing, and strict adherence to Java language specifications to prevent these common pitfalls.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaprogramming pitfalls
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.