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.
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); // trueUsing 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)); // falseAnalysis: 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 NPEBytecode 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
HashSetremoves 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 dedupedAvoidance
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.
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.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
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.
