Skip to content

Releases: jdereg/java-util

4.99.0

31 Mar 00:47

Choose a tag to compare

4.99.0 - 2026-03-28

  • FEATURE: New StringUtilities.getChars(String s) — public API that returns a ThreadLocal char[] buffer populated via String.getChars() (SIMD-optimized bulk copy). Callers can replace str.charAt(i) loops with direct buf[i] array access.
  • PERFORMANCE: StringUtilities.hashCodeIgnoreCase(String) — uses StringUtilities.getChars() into a ThreadLocal char[] buffer, then hashes from the array directly. CaseInsensitiveMap GET improved 70-75%, PUT improved 48-52%, and MIXED-CASE GET improved 68% on 100K entries.
  • PERFORMANCE: New FastReader.readLine(char[] dest, int off, int maxLen) — dedicated line-reading method optimized for TOON's line-oriented parsing. Combines scanning, copying, and line-ending consumption into a single call. JFR shows TOON line-reading improved 28%.
  • PERFORMANCE: FastReader.readUntil() pushback drain loop now uses a local variable for pushbackPosition, avoiding load/store through this on each iteration. JFR shows 14.8% reduction in FastReader CPU share.
  • PERFORMANCE: FastReader.readUntil() replaced Math.min() with inline ternary in tight buffer-scan loop. JFR confirmed 3.5% wall-clock improvement.
  • PERFORMANCE: FastReader.readUntil() now caches this.limit into a local variable after fill(). JFR shows readUntil self-time dropped ~15%.
  • PERFORMANCE: FastReader.fill() extracted core I/O into refill() which uses a local int n for the in.read() result, reducing PUTFIELD/GETFIELD overhead.

4.98.0

08 Mar 16:40

Choose a tag to compare

Changes

  • PERFORMANCE: CaseInsensitiveMap.get(), containsKey(), and remove() now use a ThreadLocal<LookupKey> for String key lookups on hash-based backings (HashMap, LinkedHashMap, ConcurrentHashMap), eliminating per-call CaseInsensitiveString allocation. This removes the single largest remaining allocation cost center (403 JFR samples). LookupKey is a lightweight mutable object reused via ThreadLocal, with bidirectional equals support for both HashMap and ConcurrentHashMap lookup directions. SortedMap backings continue to use CaseInsensitiveString since they require Comparable keys.
  • PERFORMANCE: CaseInsensitiveMap now overrides size() and isEmpty() to delegate directly to the backing map, bypassing the AbstractMap.size()entrySet().size() indirection chain (168 JFR samples eliminated).
  • PERFORMANCE: CaseInsensitiveMap internal fields changed from private to package-private to eliminate JVM synthetic accessor methods generated for anonymous inner class access (40 JFR samples eliminated).
  • PERFORMANCE: StringUtilities.hashCodeIgnoreCase() now inlines the case-fold logic directly into the hash loop, ensuring C2 JIT compiles the entire loop as a single compilation unit.
  • PERFORMANCE: StringUtilities.foldCaseForHash() branch ordering optimized to check c <= 'Z' first, partitioning ASCII so uppercase and lowercase each take only two comparisons.
  • BUG FIX: ConverterDurationToOffsetDateTimeTest used the current system timezone offset to compute expected values, but the conversion target is the epoch (1970). Fixed to compute the offset at the actual target instant.
  • TESTING: Added ToonRoundTripTest — 46 parameterized tests verifying all Converter-supported types round-trip through TOON format.
  • TESTING: Added ConverterDurationToOffsetDateTimeTest — verifies Duration → OffsetDateTime conversion across multiple scenarios.

Maven:

<dependency>
  <groupId>com.cedarsoftware</groupId>
  <artifactId>java-util</artifactId>
  <version>4.98.0</version>
</dependency>

4.97.0

08 Mar 16:40

Choose a tag to compare

Changes

  • PERFORMANCE: FastReader.readUntil() now splits the inner loop into a read-only delimiter scan followed by a bulk System.arraycopy, allowing the JIT to optimize the tight scan loop independently from memory writes.
  • PERFORMANCE: FastReader.readUntil() scan loop now uses a do-while with a single array access per iteration and hoists position assignment above the delimiter check to eliminate a duplicate write.

Maven:

<dependency>
  <groupId>com.cedarsoftware</groupId>
  <artifactId>java-util</artifactId>
  <version>4.97.0</version>
</dependency>

4.96.0

01 Mar 14:16

Choose a tag to compare

Bug Fix

  • ClassUtilities.trySetAccessible() no longer caches successful setAccessible(true) results. The WeakHashMap-based cache uses equals() for lookup, but Field.equals() matches by declaring class, name, and type — not identity. When getDeclaredFields() was called with different predicates, the JVM returned different Field instances for the same logical field; the cache returned TRUE for the second instance without ever calling setAccessible(true) on it, leaving it inaccessible. This caused Traverser to silently skip inaccessible fields, breaking GraphComparator.applyDelta(). Only failures (FALSE) are now cached to avoid expensive repeated exceptions on JPMS-sealed modules.

Install

Maven

<dependency>
  <groupId>com.cedarsoftware</groupId>
  <artifactId>java-util</artifactId>
  <version>4.96.0</version>
</dependency>

Gradle

implementation 'com.cedarsoftware:java-util:4.96.0'