Small library contracts frequently determine correctness more than API surface area. The following rules prevent common Java integration failures.
Object Contracts #
equals must be reflexive, symmetric, transitive, consistent, and false for
null. If two objects are equal, they must have the same hashCode; therefore
override both before using a value as a hash key. Do not mutate equality fields
while an object is a map key. Prefer composition over inheritance when equality
would otherwise break symmetry.
Object.clone performs a field copy and interacts poorly with constructors,
inheritance, and mutable fields. Prefer a copy constructor or a named copyOf
factory. Arrays are a narrow exception because their clone has a predictable
shallow-array contract.
Text, Regex, and Strings #
Compile a Pattern when it is reused. Matcher.matches() requires the entire
input to match, while find() searches for the next matching region.
Pattern.quote(value) escapes literal text placed into a regular expression;
Matcher.quoteReplacement(value) escapes a replacement string. These are not
interchangeable.
Since JDK 9, HotSpot’s String implementation uses compact strings: a
byte[] plus encoding marker can represent Latin-1 text compactly and UTF-16
otherwise. This is an implementation detail; Java String remains a sequence
of UTF-16 code units, and Charset conversion must be explicit at I/O
boundaries.
Counters and Enum Collections #
AtomicLong provides one exact linearizable value. LongAdder spreads updates
across cells under contention, so updates scale better but sum() is not an
atomic snapshot concurrent with updates. Use LongAdder for metrics and
AtomicLong when each observed total drives a correctness decision.
Enum<E extends Enum<E>> gives Enum type-safe ordering and operations for
one enum type. EnumSet and EnumMap exploit that closed key space and
preserve enum declaration order; prefer them to HashSet and HashMap for
enum domains.
Collections and Threads #
Thread.State reports JVM-level states such as BLOCKED, WAITING, and
TIMED_WAITING; it is observational rather than a synchronization protocol.
Use join, futures, latches, or structured ownership to coordinate threads.
Whether a Map permits null keys or values is implementation-specific:
HashMap permits one null key, while ConcurrentHashMap rejects null keys and
values, and TreeMap may reject a null key under natural ordering. Validate
the selected implementation’s contract rather than assuming the Map
interface’s optional operations succeed.
Arrays.asList(array) returns a fixed-size list backed by the supplied object
array. set updates that array, but add and remove fail. Passing int[]
creates List<int[]> with one element because varargs do not box primitive
arrays. Use Arrays.stream(ints).boxed().toList() when a list of boxed values
is required.
Comments
Read or comment on GitHub (sign-in required to comment)