or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

builder.mdclassfile.mdcollections.mdfunctional.mdindex.mdsignatures.mdstream.md

functional.mddocs/

0

# Functional Programming

1

2

Exception-safe functional programming constructs providing Result monad for robust error handling and memoization utilities for performance optimization. These utilities enable clean functional composition while maintaining Java's type safety and performance characteristics.

3

4

## Capabilities

5

6

### Result Monad

7

8

Functional result type representing either a successful value or an error, enabling exception-safe error handling patterns similar to Rust's Result or Haskell's Either.

9

10

```java { .api }

11

/**

12

* Functional result type representing either a value or an error

13

*/

14

public interface Result<V> {

15

/**

16

* Create result from value or error condition

17

* @param value Success value (null means error)

18

* @param error Error message (used if value is null)

19

* @return Result instance

20

*/

21

static <V> Result<V> of(V value, CharSequence error);

22

23

/**

24

* Create successful result

25

* @param value Success value

26

* @return Ok result containing value

27

*/

28

static <V> Result<V> ok(V value);

29

30

/**

31

* Create error result

32

* @param error Error message

33

* @return Error result

34

*/

35

static <V> Result<V> err(CharSequence error);

36

37

/**

38

* Create formatted error result

39

* @param format Error message format string

40

* @param args Format arguments

41

* @return Error result

42

*/

43

static <V> Result<V> err(String format, Object... args);

44

45

/**

46

* Check if result represents success

47

* @return true if successful, false if error

48

*/

49

boolean isOk();

50

51

/**

52

* Check if result represents error

53

* @return true if error, false if successful

54

*/

55

boolean isErr();

56

57

/**

58

* Get value as Optional

59

* @return Optional containing value if successful, empty if error

60

*/

61

Optional<V> value();

62

63

/**

64

* Get error as Optional

65

* @return Optional containing error message if error, empty if successful

66

*/

67

Optional<String> error();

68

69

/**

70

* Unwrap value or throw ResultException

71

* @return Success value

72

* @throws ResultException if result is error

73

*/

74

V unwrap();

75

76

/**

77

* Unwrap value or throw ResultException with custom message

78

* @param message Custom error message

79

* @return Success value

80

* @throws ResultException if result is error

81

*/

82

V unwrap(CharSequence message);

83

84

/**

85

* Get value or return default

86

* @param orElse Default value to return if error

87

* @return Success value or default

88

*/

89

V orElse(V orElse);

90

91

/**

92

* Get value or compute from supplier

93

* @param orElseSupplier Supplier to compute default value

94

* @return Success value or supplier result

95

*/

96

V orElseGet(SupplierWithException<? extends V> orElseSupplier);

97

98

/**

99

* Get value or throw custom exception

100

* @param throwableSupplier Function to create exception from error message

101

* @return Success value

102

* @throws R Custom exception type

103

*/

104

<R extends Throwable> V orElseThrow(FunctionWithException<? super String, ? extends R> throwableSupplier) throws R;

105

106

/**

107

* Transform success value using mapper function

108

* @param mapper Function to transform value

109

* @return Result with transformed value or original error

110

*/

111

<U> Result<U> map(FunctionWithException<? super V, ? extends U> mapper);

112

113

/**

114

* Transform error message using mapper function

115

* @param mapper Function to transform error message

116

* @return Result with transformed error or original value

117

*/

118

Result<V> mapErr(FunctionWithException<? super String, ? extends CharSequence> mapper);

119

120

/**

121

* Chain results together (monadic bind)

122

* @param mapper Function returning new Result

123

* @return Flattened result

124

*/

125

<U> Result<U> flatMap(FunctionWithException<? super V, ? extends Result<? extends U>> mapper);

126

127

/**

128

* Recover from error by computing new value

129

* @param recover Function to compute recovery value from error

130

* @return Result with recovered value or original success

131

*/

132

Result<V> recover(FunctionWithException<? super String, ? extends V> recover);

133

134

/**

135

* Recover from error by computing new Result

136

* @param recover Function to compute recovery Result from error

137

* @return Recovered result or original success

138

*/

139

Result<V> recoverWith(FunctionWithException<? super String, ? extends Result<? extends V>> recover);

140

141

/**

142

* Process result with separate handlers for success and error

143

* @param ok Handler for success value

144

* @param err Handler for error message

145

*/

146

void accept(ConsumerWithException<? super V> ok, ConsumerWithException<? super String> err);

147

148

/**

149

* Cast error result to different value type

150

* @return Error result with different type parameter

151

*/

152

<U> Result<U> asError();

153

}

154

155

/**

156

* Exception thrown when unwrapping failed results

157

*/

158

public class ResultException extends RuntimeException {

159

public ResultException(String message);

160

public ResultException(Exception cause);

161

}

162

```

163

164

**Usage Examples:**

165

166

```java

167

import aQute.bnd.result.Result;

168

169

// Basic usage

170

Result<Integer> divide(int a, int b) {

171

if (b == 0) {

172

return Result.err("Division by zero");

173

}

174

return Result.ok(a / b);

175

}

176

177

Result<Integer> result = divide(10, 2);

178

if (result.isOk()) {

179

System.out.println("Result: " + result.unwrap()); // Result: 5

180

} else {

181

System.out.println("Error: " + result.error().get());

182

}

183

184

// Functional composition

185

Result<String> processNumber(int input) {

186

return divide(input, 2)

187

.map(x -> x * 3)

188

.map(x -> "Processed: " + x)

189

.recover(err -> "Default processed value");

190

}

191

192

// Chain operations

193

Result<Integer> chainedOperation = Result.ok(10)

194

.flatMap(x -> divide(x, 2))

195

.flatMap(x -> divide(x, 2))

196

.recover(err -> 0);

197

198

// Error handling without exceptions

199

String result = divide(10, 0)

200

.map(x -> "Success: " + x)

201

.orElse("Operation failed");

202

```

203

204

### Memoization

205

206

Caching utilities for expensive computations with various eviction strategies and resource management options.

207

208

```java { .api }

209

/**

210

* Memoizing supplier interface that caches computed values

211

*/

212

public interface Memoize<S> extends Supplier<S> {

213

/**

214

* Create basic memoizing supplier

215

* @param supplier Supplier to memoize

216

* @return Memoizing supplier that computes once and caches result

217

*/

218

static <T> Memoize<T> supplier(Supplier<? extends T> supplier);

219

220

/**

221

* Create memoizing supplier from function and argument

222

* @param function Function to memoize

223

* @param argument Function argument

224

* @return Memoizing supplier

225

*/

226

static <T, R> Memoize<R> supplier(Function<? super T, ? extends R> function, T argument);

227

228

/**

229

* Create time-based refreshing memoizing supplier

230

* @param supplier Supplier to memoize

231

* @param time_to_live Time to live for cached value

232

* @param unit Time unit for TTL

233

* @return Refreshing memoizing supplier

234

*/

235

static <T> Memoize<T> refreshingSupplier(Supplier<? extends T> supplier, long time_to_live, TimeUnit unit);

236

237

/**

238

* Create reference-based memoizing supplier

239

* @param supplier Supplier to memoize

240

* @param reference Function to create reference for caching

241

* @return Reference-based memoizing supplier

242

*/

243

static <T> Memoize<T> referenceSupplier(Supplier<? extends T> supplier, Function<? super T, ? extends Reference<? extends T>> reference);

244

245

/**

246

* Create predicate-based memoizing supplier

247

* @param supplier Supplier to memoize

248

* @param predicate Predicate to test if cached value is still valid

249

* @return Predicate-based memoizing supplier

250

*/

251

static <T> Memoize<T> predicateSupplier(Supplier<? extends T> supplier, Predicate<? super T> predicate);

252

253

/**

254

* Get memoized value (inherited from Supplier)

255

* @return Cached or computed value

256

*/

257

S get();

258

259

/**

260

* Peek at memoized value without triggering computation

261

* @return Cached value or null if not computed

262

*/

263

S peek();

264

265

/**

266

* Check if value has been computed and cached

267

* @return true if value is cached, false otherwise

268

*/

269

boolean isPresent();

270

271

/**

272

* Transform memoized value using mapper function

273

* @param mapper Function to transform cached value

274

* @return New memoized supplier with transformed value

275

*/

276

<R> Memoize<R> map(Function<? super S, ? extends R> mapper);

277

278

/**

279

* Chain memoized suppliers together

280

* @param mapper Function returning new supplier

281

* @return Flattened memoized supplier

282

*/

283

<R> Memoize<R> flatMap(Function<? super S, ? extends Supplier<? extends R>> mapper);

284

285

/**

286

* Filter memoized value with predicate

287

* @param predicate Filter predicate

288

* @return Filtered memoized supplier

289

*/

290

Memoize<S> filter(Predicate<? super S> predicate);

291

292

/**

293

* Apply consumer to memoized value

294

* @param consumer Consumer to apply

295

* @return This memoized supplier

296

*/

297

Memoize<S> accept(Consumer<? super S> consumer);

298

299

/**

300

* Apply consumer if value is present

301

* @param consumer Consumer to apply

302

* @return This memoized supplier

303

*/

304

Memoize<S> ifPresent(Consumer<? super S> consumer);

305

}

306

307

/**

308

* Memoizing supplier for AutoCloseable resources

309

*/

310

public interface CloseableMemoize<S extends AutoCloseable> extends Memoize<S>, AutoCloseable {

311

/**

312

* Create closeable memoizing supplier

313

* @param supplier Supplier producing AutoCloseable resources

314

* @return Closeable memoizing supplier

315

*/

316

static <T extends AutoCloseable> CloseableMemoize<T> closeableSupplier(Supplier<? extends T> supplier);

317

318

/**

319

* Check if this memoizing supplier is closed

320

* @return true if closed, false otherwise

321

*/

322

boolean isClosed();

323

324

/**

325

* Get the memoized AutoCloseable value

326

* @return The memoized AutoCloseable value

327

* @throws IllegalStateException if this supplier is closed

328

*/

329

@Override

330

S get();

331

332

/**

333

* Apply consumer to memoized value (thread-safe with closing)

334

* @param consumer Consumer to apply

335

* @return This memoized supplier

336

* @throws IllegalStateException if this supplier is closed

337

*/

338

@Override

339

CloseableMemoize<S> accept(Consumer<? super S> consumer);

340

341

/**

342

* Apply consumer if value is present (thread-safe with closing)

343

* @param consumer Consumer to apply

344

* @return This memoized supplier

345

*/

346

@Override

347

CloseableMemoize<S> ifPresent(Consumer<? super S> consumer);

348

349

/**

350

* Close the cached resource if present

351

* @throws Exception if closing fails

352

*/

353

void close() throws Exception;

354

}

355

```

356

357

**Usage Examples:**

358

359

```java

360

import aQute.bnd.memoize.Memoize;

361

import aQute.bnd.memoize.CloseableMemoize;

362

import java.util.concurrent.TimeUnit;

363

364

// Basic memoization

365

Memoize<String> expensiveResult = Memoize.supplier(() -> {

366

// Expensive computation

367

Thread.sleep(1000);

368

return "Computed result";

369

});

370

371

String result1 = expensiveResult.get(); // Takes 1 second

372

String result2 = expensiveResult.get(); // Instant (cached)

373

374

// Time-based refresh

375

Memoize<Date> currentTime = Memoize.refreshingSupplier(

376

() -> new Date(),

377

5, TimeUnit.MINUTES

378

);

379

380

// Reference-based caching (e.g., weak references)

381

Memoize<LargeObject> weakCached = Memoize.referenceSupplier(

382

() -> new LargeObject(),

383

WeakReference::new

384

);

385

386

// Predicate-based validation

387

Memoize<Configuration> config = Memoize.predicateSupplier(

388

() -> loadConfiguration(),

389

cfg -> cfg.isValid()

390

);

391

392

// Transform cached values

393

Memoize<Integer> length = expensiveResult.map(String::length);

394

395

// Closeable resources

396

try (CloseableMemoize<Connection> connection = CloseableMemoize.closeableSupplier(

397

() -> DriverManager.getConnection(url))) {

398

399

Connection conn = connection.get();

400

// Use connection

401

} // Automatically closes cached connection

402

```

403

404

## Functional Exception Handling

405

406

Extended functional interfaces that properly handle exceptions in functional pipelines.

407

408

```java { .api }

409

/**

410

* Function that can throw exceptions

411

*/

412

@FunctionalInterface

413

public interface FunctionWithException<T, R> {

414

R apply(T t) throws Exception;

415

}

416

417

/**

418

* Consumer that can throw exceptions

419

*/

420

@FunctionalInterface

421

public interface ConsumerWithException<T> {

422

void accept(T t) throws Exception;

423

}

424

425

/**

426

* Supplier that can throw exceptions

427

*/

428

@FunctionalInterface

429

public interface SupplierWithException<T> {

430

T get() throws Exception;

431

}

432

```