Class Resource<T>
- Type Parameters:
T- the type of the managed resource value
Resource<T> is the composable alternative to try-with-resources.
Acquisition and release are declared together at construction time. The resource is only
live during the execution of use(fn) — it is acquired just
before the body runs, and the release function is always called when the body
completes, whether it succeeds or throws.
Behaviour contract
- If the body succeeds and release succeeds →
Try.success(result). - If the body succeeds but release throws →
Try.failure(releaseException). - If the body throws and release succeeds →
Try.failure(bodyException). - If both the body and release throw → the release exception is suppressed onto
the body exception (mirroring
try-with-resourcessemantics) andTry.failure(bodyException)is returned.
Composition
-
Method Summary
Modifier and TypeMethodDescriptionstatic <T> Resource<T> eval(Try<? extends T> acquired, CheckedConsumer<? super T> release) Creates aResource<T>from a pre-computedTry<T>and a release function.<R> Resource<R> Sequences this resource with an inner resource derived from its value.static <T extends AutoCloseable>
Resource<T> fromAutoCloseable(CheckedSupplier<? extends T> acquire) Creates aResource<T>from anAutoCloseablesupplier.<R> Resource<R> Returns a newResource<R>whose body receives the result of applyingfnto the acquired value.<R> Resource<R> Returns a newResource<R>whose value is obtained by applying aTry-returning function to the acquired value.static <T> Resource<T> of(CheckedSupplier<? extends T> acquire, CheckedConsumer<? super T> release) Creates aResource<T>from explicit acquire and release functions.<R> Try<R> use(CheckedFunction<? super T, ? extends R> body) Acquires the resource, appliesbodyto it, releases the resource, and returns the body's result wrapped in aTry.<R,E> Result <R, E> useAsResult(Function<? super T, ? extends Result<? extends R, ? extends E>> body, Function<? super Throwable, ? extends E> onError) Acquires the resource, appliesbodyto produce aResult, releases the resource, and returns aResult<R, E>.
-
Method Details
-
of
public static <T> Resource<T> of(CheckedSupplier<? extends T> acquire, CheckedConsumer<? super T> release) Creates aResource<T>from explicit acquire and release functions.Example:
Resource<Connection> conn = Resource.of( () -> dataSource.getConnection(), Connection::close );- Type Parameters:
T- the resource type- Parameters:
acquire- supplier that obtains the resource; may throwrelease- consumer that frees the resource; always called after the body- Returns:
- a new
Resource<T> - Throws:
NullPointerException- ifacquireorreleaseisnull
-
fromAutoCloseable
public static <T extends AutoCloseable> Resource<T> fromAutoCloseable(CheckedSupplier<? extends T> acquire) Creates aResource<T>from anAutoCloseablesupplier. TheAutoCloseable.close()method is used as the release function.Example:
Resource<BufferedReader> reader = Resource.fromAutoCloseable( () -> new BufferedReader(new FileReader(path)) ); Try<String> content = reader.use(r -> r.lines().collect(joining("\n")));- Type Parameters:
T- the resource type, must extendAutoCloseable- Parameters:
acquire- supplier that obtains theAutoCloseableresource; may throw- Returns:
- a new
Resource<T> - Throws:
NullPointerException- ifacquireisnull
-
eval
Creates aResource<T>from a pre-computedTry<T>and a release function.If
acquiredis already a failure,usereturns that failure immediately and thereleasefunction is never called — there is nothing to release.One-shot contract: because the resource value is pre-computed rather than freshly acquired on each call, invoking
use()more than once on the returnedResourcewill callreleaseon the same underlying value each time. If the resource is not idempotent with respect to release (e.g., a JDBCConnectionor an I/O stream), callinguse()more than once produces undefined behaviour. Preferof()when reuse is required, as it acquires a fresh resource on every call.Example:
Try<Connection> tryConn = Try.of(() -> dataSource.getConnection()); Resource<Connection> conn = Resource.eval(tryConn, Connection::close); Try<List<User>> users = conn.use(c -> fetchUsers(c)); // call use() exactly once- Type Parameters:
T- the resource type- Parameters:
acquired- the pre-computed result of an acquire attempt; if failure, release is skippedrelease- consumer that frees the resource when acquired successfully- Returns:
- a new
Resource<T>backed by the pre-computedacquiredvalue - Throws:
NullPointerException- ifacquiredorreleaseisnull
-
use
Acquires the resource, appliesbodyto it, releases the resource, and returns the body's result wrapped in aTry.The release function is always called, even when
bodythrows. See the class-level contract for the exact exception-merging rules.- Type Parameters:
R- the result type- Parameters:
body- function applied to the live resource; may throw- Returns:
Try.success(result)on success, orTry.failure(cause)on any error- Throws:
NullPointerException- ifbodyisnull
-
useAsResult
public <R,E> Result<R,E> useAsResult(Function<? super T, ? extends Result<? extends R, ? extends E>> body, Function<? super Throwable, ? extends E> onError) Acquires the resource, appliesbodyto produce aResult, releases the resource, and returns aResult<R, E>.This is the
Result-integrated variant ofuse(). It is useful when the domain layer models failures as typedResultvalues rather thanThrowable.- If acquire or release throws a
Throwable, it is mapped toEviaonErrorand returned asResult.err(e). - If the body returns
Result.err(e), that error is returned as-is. - If both body and release fail, the release exception is suppressed onto the body
exception and the combined throwable is passed to
onError.
Example:
Result<List<User>, DbError> users = connResource.useAsResult( conn -> fetchUsers(conn), ex -> new DbError.QueryFailed(ex.getMessage()) );- Type Parameters:
R- the success typeE- the error type- Parameters:
body- function applied to the live resource; returns aResultonError- maps anyThrowablefrom acquire/release/body toE- Returns:
Result.ok(value)on success, orResult.err(error)on any failure- Throws:
NullPointerException- ifbodyoronErrorisnull
- If acquire or release throws a
-
map
Returns a newResource<R>whose body receives the result of applyingfnto the acquired value. The acquire/release lifecycle of the underlying resource is unchanged.If
fnthrows, the underlying resource is still released and the exception is captured as aTry.failure.- Type Parameters:
R- the mapped resource type- Parameters:
fn- function transforming the acquired value; must not benull- Returns:
- a new
Resource<R> - Throws:
NullPointerException- iffnisnull
-
flatMap
Sequences this resource with an inner resource derived from its value. Both resources are released in reverse acquisition order: the inner resource is released first, then this (outer) resource.Example — connection then prepared statement:
Resource<PreparedStatement> stmt = connResource.flatMap(c -> Resource.of( () -> c.prepareStatement("SELECT * FROM users"), PreparedStatement::close ) ); Try<List<User>> result = stmt.use(ps -> mapRows(ps.executeQuery()));- Type Parameters:
R- the inner resource type- Parameters:
fn- function that produces the inner resource from this resource's value; must not benulland must not returnnull- Returns:
- a composed
Resource<R>whose lifecycle manages both resources - Throws:
NullPointerException- iffnisnullor returnsnull
-
mapTry
Returns a newResource<R>whose value is obtained by applying aTry-returning function to the acquired value.This is the
Try-integrated counterpart ofmap(). It is useful when the transformation itself is a fallible operation already wrapped in aTry(e.g., parsing, validation, or a call to aTry.of(...)-wrapped API). Iffnreturns a failure, the underlying resource is still released and the failure is propagated.Example:
Resource<Config> config = rawTextResource.mapTry(text -> Try.of(() -> Config.parse(text)) ); Try<Integer> port = config.use(c -> c.port());- Type Parameters:
R- the mapped resource type- Parameters:
fn- function returning aTry<R>; must not benullor returnnull- Returns:
- a new
Resource<R> - Throws:
NullPointerException- iffnisnull
-