Common Java functionality. The implementations in this library are intended to solve simple problems in simple ways.
Gradle:
implementation 'com.autonomouslogic.commons:commons-java:version'
Maven:
<dependency>
<groupId>com.autonomouslogic.commons</groupId>
<artifactId>commons-java</artifactId>
<version>version</version>
</dependency>
Wraps a Supplier and caches its result, so the underlying logic runs only once.
Useful for expensive operations like opening database connections or loading large datasets.
Supplier<DatabaseConnection> supplier = () -> new DatabaseConnection();
CachedSupplier<DatabaseConnection> cached = new CachedSupplier<>(supplier);
cached.get(); // Creates connection
cached.get(); // Returns cached connection (no new creation)Utilities for combining lists. Two approaches depending on your needs:
-
concat()— Combines lists into a read-only view without copying elements. Useful for iteration and searching across multiple lists as one logical sequence.List<String> first = List.of("a", "b"); List<String> second = List.of("c", "d"); List<String> combined = ListUtil.concat(first, second); // lightweight, no copy combined.size(); // 4 combined.get(2); // "c"
-
concatCopy()— Copies all elements from multiple lists into a new ArrayList. Useful when you need a mutable list or standalone data.List<String> combined = ListUtil.concatCopy(first, second); // new ArrayList with all elements combined.add("e"); // works, unlike concat()
Utilities for combining sets.
-
mergeCopy()— Merges multiple sets into a new LinkedHashSet. Duplicates are automatically handled.Set<String> colors1 = Set.of("red", "blue"); Set<String> colors2 = Set.of("blue", "green"); Set<String> merged = SetUtil.mergeCopy(colors1, colors2); // {red, blue, green}
-
addAll()— Adds elements from multiple sets to an existing target set (in-place).Set<String> existing = new HashSet<>(); SetUtil.addAll(existing, Set.of("apple"), Set.of("banana"));
Builder-based configuration reader that parses environment variables into typed values with fallback defaults. Supports many types out-of-the-box (Integer, Boolean, Duration, URI, etc.) and file-based secret injection.
// Define configs statically
public class AppConfig {
public static final Config<String> ENVIRONMENT = Config.<String>builder()
.name("ENVIRONMENT")
.type(String.class)
.defaultValue("dev")
.build();
public static final Config<Integer> PORT = Config.<Integer>builder()
.name("PORT")
.type(Integer.class)
.defaultValue(8080)
.build();
}
// Read values
Optional<String> env = AppConfig.ENVIRONMENT.get(); // with default
Integer port = AppConfig.PORT.getRequired(); // throws if not setFile-based secrets: set PORT_FILE=/run/secrets/port to read from a file instead of the PORT variable directly.
Loads resources (files) from the classpath and throws clear exceptions if resources are not found. Particularly useful for loading configuration files and test fixtures, with contextual loading for organizing test data by test class.
// Load from classpath
try (var in = ResourceUtil.loadResource("/config.json")) {
var config = new String(in.readAllBytes());
}
// Load test fixtures organized by test class
// For class com.example.MyTest, loads from /com/example/MyTest/data.json
try (var in = ResourceUtil.loadContextual(MyTest.class, "/data.json")) {
var data = new String(in.readAllBytes());
}Throws FileNotFoundException with the missing path if a resource doesn't exist, unlike standard Java
resource loading which returns null. Two methods: loadResource() for absolute/package-relative paths,
loadContextual() for paths relative to a test class's directory.
RxJava 3 utilities for non-blocking async operations and stream processing.
Key methods:
-
toSingle(),toMaybe(),toCompletable()— Convert CompletionStage to RxJava types (non-blocking, unlike fromFuture) -
retryWithDelayFlowable()— Retry streams with configurable delay and error filtering -
orderedMerge()— Merge sorted streams while maintaining order -
zipAllFlowable()— Zip streams until all complete (vs standard zip which stops at shortest) -
wrapTransformerErrors()— Wrap transformer errors with context for debugging -
windowSort()— Sort stream items within a sliding window -
checkOrder()— Verify stream is strictly ordered, error if not
Simple stopwatch for measuring elapsed time with nanosecond precision using System.nanoTime().
Supports multiple start/stop cycles with accumulated time, useful for benchmarking and performance monitoring.
Stopwatch watch = Stopwatch.start();
doWork();
watch.stop();
System.out.println("Elapsed: " + watch.getDuration());
// Resume measuring and accumulate more time
watch.restart();
doMoreWork();
watch.stop();
System.out.println("Total: " + watch.getDuration()); // combined time from both cyclesKey methods: start() creates and starts a stopwatch, stop() accumulates time, restart() resumes measurement,
getNanos() gets total nanoseconds, getDuration() gets total as Duration. Idempotent: calling stop/restart
multiple times won't cause errors.
Executes I/O-bound tasks on virtual threads with bounded concurrency. Virtual threads are lightweight and can handle blocking I/O efficiently without tying up platform threads for APIs, database calls, and file operations.
Key capabilities:
-
callAll()- Execute callables/functions and collect results in submission orderList<String> urls = List.of("https://api1.com", "https://api2.com"); List<String> responses = VirtualThreads.callAll(urls, url -> fetchUrl(url), 2); // results in order: responses.get(0) is from urls.get(0)
-
runAll()- Execute runnables with bounded concurrency (no results)List<String> files = List.of("file1.txt", "file2.txt", "file3.txt"); VirtualThreads.runAll(files, filename -> processFile(filename), 5);
-
isVirtual()/checkIsVirtual()- Detect if running on a virtual threadif (VirtualThreads.isVirtual()) { // Safe to block on I/O without hurting throughput }
-
onVirtualThread()- Execute a task on a virtual thread if not already on oneString result = VirtualThreads.onVirtualThread(() -> blockingDatabaseCall());
This project follows semantic versioning.
This project follows Palantir with tabs.
Automatic code formatting can be done by running ./gradlew spotlessApply.
This project is licensed under the MIT-0 license.
| Type | Status |
|---|---|
| CodeClimate | |
| SonarCloud | |
| Libraries.io | |
| Snyk | |
| Codecov | |
| Synatype Lift | link |