0.0.1

for-comprehension
4j

Bring Scala's for-expression syntax to Java. Compose Optional, Stream, and Iterable without deep nesting. Eager and lazy evaluation with optional filter/guard clauses.

com.pivovarit:for-comprehension4j:0.0.1 click to copy

No more flatMap
spaghetti

Flatten nested monadic chains into clean, readable comprehensions — the way Scala does it.

Scala-inspired

Brings Scala's for-expression syntax to Java, eliminating deeply nested flatMap and map chains.

Multiple types

Supports Optional, Stream, and Iterable out of the box, with consistent semantics across all container types.

Eager & Lazy

Eager mode for independent values provided upfront; lazy mode when later bindings depend on earlier ones.

Filter / Guards

Optional .filter() step that acts as a guard clause. Multiple calls are AND-composed automatically.

Fluent API

Chain bindings naturally and terminate with .yield() to produce the result. Clean and readable at any arity.

JDK 8+

Compatible with Java 8 and above. No exotic runtime requirements, no virtual threads, no module system.

Comprehensions
in practice

All examples use import static com.pivovarit.forc.ForComprehension.forc;

// Eager: all values known upfront
Optional<Integer> width  = Optional.of(3);
Optional<Integer> height = Optional.of(4);

Optional<Integer> area = forc(width, height)
  .yield((w, h) -> w * h);

// area -> Optional[12]

// Lazy: second value depends on first
Optional<Integer> area2 = forc(
    Optional.of(3),
    w -> Optional.of(w + 1)
  ).yield((w, h) -> w * h);

// area2 -> Optional[12]
// Eager: cartesian product
Stream<Integer> result = forc(
    Stream.of(1, 2),
    Stream.of(10, 20)
  ).yield(Integer::sum);

// result -> [11, 21, 12, 22]

// Lazy: second stream depends on first
Stream<Integer> result2 = forc(
    Stream.of(1, 2),
    v1 -> Stream.of(v1 * 10, v1 * 20)
  ).yield(Integer::sum);

// result2 -> [11, 21, 22, 42]
// Eager
List<Integer> result = forc(
    List.of(1, 2),
    List.of(10, 20)
  ).yield(Integer::sum);

// result -> [11, 21, 12, 22]

// Lazy
List<Integer> result2 = forc(
    List.of(1, 2),
    v1 -> List.of(v1 * 10, v1 * 20)
  ).yield(Integer::sum);

// result2 -> [11, 21, 22, 42]
// Optional — guard failure produces empty()
Optional<Integer> area = forc(
    Optional.of(4), Optional.of(3)
  ).filter((w, h) -> w > h)
   .yield((w, h) -> w * h);
// area -> Optional[12]  (4 > 3, guard passes)

// Stream — guard filters the cartesian product
Stream<String> allowed = forc(
    Stream.of("admin", "user"),
    Stream.of("read", "write")
  ).filter((role, scope) -> !(role.equals("user") && scope.equals("write")))
   .yield((role, scope) -> role + ":" + scope);
// allowed -> ["admin:read", "admin:write", "user:read"]

Core operations

Static factory method forc() on ForComprehension — inspired by Scala's for/yield expressions.

forc(v1, v2, ...) → Comprehension

Eager overload. All values are provided upfront. The result type mirrors the container (Optional → Optional, Stream → Stream, Iterable → List).

forc(v1, fn2, ...) → Comprehension

Lazy overload. Later values are functions of the preceding ones, enabling dependent bindings where each step can reference earlier results.

.filter(predicate) → Comprehension

Guard clause. Keeps only combinations where the predicate holds. Multiple .filter() calls are AND-composed automatically.

.yield(fn) → R

Terminal operation. Applies the mapping function to all bound values and produces the final result: Optional<R>, Stream<R>, or List<R>.

// All types use the same forc() + .yield() pattern

// Optional → Optional<R>
Optional<String> r1 = forc(Optional.of("a"), Optional.of("b"))
  .yield((a, b) -> a + b);

// Stream → Stream<R>  (cartesian product)
Stream<String> r2 = forc(Stream.of("x", "y"), Stream.of("1", "2"))
  .yield((a, b) -> a + b);

// Iterable → List<R>
List<String> r3 = forc(List.of("x", "y"), List.of("1", "2"))
  .yield((a, b) -> a + b);

Add to your project

Maven

JDK 8+
<dependency>
  <groupId>com.pivovarit</groupId>
  <artifactId>for-comprehension4j</artifactId>
  <version>0.0.1</version>
</dependency>

Gradle

JDK 8+
implementation 'com.pivovarit:for-comprehension4j:0.0.1'
Available on Maven Central. Requires Java 8 or above.