- Type Parameters:
A
- The parent type with the field of typeB
to be focused on.B
- The type of the field to be focused on in the parent typeA
.
The
Lens
interface defines an access and update operation on an individual part of a nested and immutable
data structure. A lens can also be composed with other lenses to focus on more deeply nested parts.
This design concept is part of the functional programming paradigm, and it emulates
mutable properties (getter and setter) in an immutable world using a getter and more importantly
a wither methods (a function that returns a new structure with target field being updated).
So a Lenses encapsulate two essential operations:
- getter: Extracts a specific field from a parent type.
- wither: Produces a new instance of the parent with an updated field, preserving immutability.
Usage Example:
record Person(String name, Address address) {}
record Address(String street, String city) {}
Lens<Person, Address> addressLens = Lens.of(
Person::address,
(person, newAddress) -> new Person(person.name(), newAddress)
);
Lens<Address, String> streetLens = Lens.of(
Address::street,
(address, newStreet) -> new Address(newStreet, address.city())
);
Lens<Person, String> personStreetLens = addressLens.to(streetLens);
Person person = new Person("Alice", new Address("1st Ave", "Wonderland"));
String street = personStreetLens.getter(person); // "1st Ave"
Person updatedPerson = personStreetLens.wither(person, "2nd Ave");
Composability:
You may compose lenses using the to(Lens)
method, which composes them into a new lens,
enabling seamless traversal and modification of deeply nested structures.
Factory Method:
Theof(Function, BiFunction)
static method is provided to easily create lenses from lambda expressions.-
Method Summary
Modifier and TypeMethodDescriptionacross
(Class<B> type, Function<A, B> getter, BiFunction<A, B, A> wither) Creates a lens that operates across all elements of aTuple
, allowing bulk transformations of homogeneous data structures.Extracts the field of typeB
from the parent typeA
and returns it or throws an exception if an error occurs while extracting the field.static <A,
B> Lens <A, B> of
(Function<A, B> getter, BiFunction<A, B, A> wither) Creates a new lens from the given getter and wither functions, where the first function serves as an implementation ofgetter(Object)
and the second function serves as an implementation ofwither(Object, Object)
.Combines this lens with a pair of getter and wither functions, to create a new lens that focuses on a more deeply nested field.Composes this lens with another lens, creating a new lens that focuses on a more deeply nested field.Produces a new instance of the parent typeA
with one of its fields of typeB
updated with a new value.
-
Method Details
-
of
Creates a new lens from the given getter and wither functions, where the first function serves as an implementation ofgetter(Object)
and the second function serves as an implementation ofwither(Object, Object)
.- Type Parameters:
A
- The parent type with the field of typeB
to be focused on.B
- The type of the field to be focused on in the parent typeA
.- Parameters:
getter
- The function that extracts the field of typeB
from the parent typeA
.wither
- The function that produces a new instance of the parent typeA
with the field updated.- Returns:
- A new lens instance.
- Throws:
NullPointerException
- If either of the given functions isnull
.
-
across
static <A,B> Lens<Tuple<A>,Tuple<B>> across(Class<B> type, Function<A, B> getter, BiFunction<A, B, A> wither) Creates a lens that operates across all elements of aTuple
, allowing bulk transformations of homogeneous data structures. This is particularly useful for scenarios like multi-selection where you want to apply the same lens operation to multiple values simultaneously.The returned lens will:
-
Use the provided
getter
to extract a property of typeB
from each element of typeA
in the tuple. -
Use the provided
wither
to update that propertyB
across all elementsA
in the tuple.
You may then use such a lens to zoom into a tuple-based property to get a tuple-based lens property:record Person(String name, int age) { public Person withAge(int newAge) { return new Person(name, newAge); } } // Create tuple lens version Lens<Tuple<Person>, Tuple<Integer>> bulkAgeLens = Lens.across( Integer.class,Person::age, Person::withAge ); Tuple<Person> people = Tuple.of( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 35) ); // Get all ages Tuple<Integer> ages = bulkAgeLens.getter(people); // (30, 25, 35) // Set all ages to 40 Tuple<Person> updatedPeople = bulkAgeLens.wither(people, Tuple.of(40, 40, 40));
Var<Tuple<Person>> people = getPeople(); Var<Tuple<Integer> ages = people.zoomTo( Lens.across( Integer.class, Person::age, Person::withAge ));
- Type Parameters:
A
- The element type contained in the source tupleB
- The type of property being focused on in each element- Parameters:
type
- The class object for typeB
, used for tuple type safetygetter
- Function to extract propertyB
from a singleA
wither
- Function to update propertyB
in a singleA
- Returns:
- A lens that operates on tuples of
A
to get/set tuples ofB
- Throws:
NullPointerException
- if either getter or wither is nullIllegalArgumentException
- during wither operation if input tuples have different sizes
-
Use the provided
-
getter
Extracts the field of typeB
from the parent typeA
and returns it or throws an exception if an error occurs while extracting the field.- Parameters:
parentValue
- The parent object to extract the field from.- Returns:
- The field of type
B
from the parent object. - Throws:
Exception
- If an error occurs while extracting the field.
-
wither
Produces a new instance of the parent typeA
with one of its fields of typeB
updated with a new value. The parent object is not modified, and a new instance is returned.- Parameters:
parentValue
- The parent object to update the field in.newValue
- The new value to update the field with.- Returns:
- A new instance of the parent type
A
with the field updated. - Throws:
Exception
- If an error occurs while updating the field.
-
to
Composes this lens with another lens, creating a new lens that focuses on a more deeply nested field. This lens focuses on a field of typeB
in the parent typeA
, and the other lens focuses on a field of typeC
in the parent typeB
. The composed lens will focus on a field of typeC
in the parent typeA
, effectively traversing two levels of nesting and side-stepping the intermediate parent typeB
.- Type Parameters:
C
- The type of the field to be focused on in the parent typeB
.- Parameters:
other
- The other lens to compose with this lens.- Returns:
- A new lens that focuses on a more deeply nested field.
- Throws:
NullPointerException
- If the given lens isnull
.
-
to
Combines this lens with a pair of getter and wither functions, to create a new lens that focuses on a more deeply nested field. This lens focuses on a field of typeB
in the parent typeA
, and the two supplied lambdas focus on a field of typeC
in the parent typeB
. The composed lens will focus on a field of typeC
in the parent typeA
, effectively traversing two levels of nesting and side-stepping the intermediate parent typeB
.- Type Parameters:
C
- The type of the field to be focused on in the parent typeB
.- Parameters:
getter
- The function that extracts the field of typeC
from the parent typeB
.wither
- The function that produces a new instance of the parent typeB
with the field updated.- Returns:
- A new lens that focuses on a more deeply nested field.
- Throws:
NullPointerException
- If either of the given functions isnull
.
-