public interface Box<T> extends Supplier<T>, Consumer<T>
Provides get/set access to a mutable non-null value. See Box.Nullable
if you need the ability to handle null values, or Box.Dbl
, Box.Int
, or Box.Lng
if you’d like better performance for primitive values.
Some implementations may provide atomicity or concurrency guarantees around the modify(Function)
method, but this is not required of Box
in general.
All implementations have a map(Converter)
method for transforming the underlying storage location and making it appear to hold a different kind of value. Any atomicity guarantees of modify
are maintained by map
.
The primary use cases for Box
are:
It’s often helpful for a lambda to hold some state, but lambdas can only reference variables which are effectively final. Boxes make it easy to circumvent this limitation.
public static Consumer<String> stringsToLines(Consumer<String> perLine) {
Box<String> leftover = Box.of("");
return rawString -> {
int lastIdx = 0;
int idx = 0;
while ((idx = rawString.indexOf('\n', lastIdx)) > -1) {
perLine.accept(rawString.substring(lastIdx, idx));
lastIdx = idx + 1;
}
leftover.set(rawString.substring(lastIdx));
};
}
Let’s say you’ve got various game entities that you’re drawing on a screen:
class SpaceShip { Point2D p; }
class Bullet {
int getX(); void setX(int x);
int getY(); void setY(int y);
}
You’d like to present their position to some animation mechanism in a general way. With boxes, you could do it like this:
SpaceShip ship = ...
Box<Point2D> shipPos = Box.from(
() -> ship.p,
value -> { ship.p = value; });
Bullet bullet = ...
Box<Point2D> bulletPos = Box.from(
() -> new Point2D(bullet.getX(), bullet.getY()),
value -> {
bullet.setX(value.x);
bullet.setY(value.y);
});
// and for testing
Box<Point2D> testPos = Box.of(new Point2D(0, 0));
animationApi.animate(shipPos ).from(0, 0).to(10, 10);
animationApi.animate(bulletPos).from(0, 0).to(10, 10);
animationApi.animate(testPos ).from(0, 0).to(10, 10);
Modifier and Type | Interface and Description |
---|---|
static interface |
Box.Dbl
A
Box for primitive doubles. |
static interface |
Box.Int
A
Box for primitive ints. |
static interface |
Box.Lng
A
Box for primitive longs. |
static interface |
Box.Nullable<T>
A
Box which allows nulls. |
Modifier and Type | Method and Description |
---|---|
default void |
accept(T value)
|
static <T> Box<T> |
from(Supplier<T> getter,
Consumer<T> setter)
Creates a
Box from a Supplier and a Consumer . |
default <R> Box<R> |
map(Converter<T,R> converter)
Maps one
Box to another Box , preserving any modify(Function) concurrency guarantees of the underlying Box. |
default T |
modify(Function<? super T,? extends T> mutator)
Performs a set() on the result of a get().
|
static <T> Box<T> |
of(T value)
Creates a
Box holding the given value in a non-volatile field. |
static <T> Box<T> |
ofVolatile(T value)
Creates a
Box holding the given value in a volatile field. |
void |
set(T value)
Sets the value which will later be returned by get().
|
void set(T value)
Sets the value which will later be returned by get().
@Deprecated default void accept(T value)
Delegates to set(T)
.
default T modify(Function<? super T,? extends T> mutator)
Performs a set() on the result of a get().
Some implementations may provide atomic semantics, but it’s not required.
default <R> Box<R> map(Converter<T,R> converter)
Maps one Box
to another Box
, preserving any modify(Function)
concurrency guarantees of the underlying Box.
static <T> Box<T> of(T value)
Creates a Box
holding the given value in a non-volatile
field.
modify()
is just a shortcut for set(function.apply(get()))
.
static <T> Box<T> ofVolatile(T value)
Creates a Box
holding the given value in a volatile
field.
modify()
is just a shortcut for set(function.apply(get()))
, use AtomicReference
if you require atomic semantics.