public final class ConsumerUtils
extends java.lang.Object
| Modifier and Type | Method and Description |
|---|---|
static <T,U> java.util.function.Consumer<T> |
consumer(java.util.function.BiConsumer<? super T,? super U> biConsumer,
U value)
Builds a consumer from a passed
BiConsumer, which can be very useful in the common situation where
you are streaming through a collection of elements, and have a method to call that takes two parameters - the
first one being the element on which you are streaming, and the second being some constant value that will be
passed to all invocations. |
static <T> java.util.function.Consumer<T> |
consumer(java.util.function.Consumer<T> consumer)
Simply casts a method reference, which takes a single parameter of type <T> and returns void, to a
Consumer. |
static <T> java.util.function.Consumer<T> |
consumer(java.lang.Runnable runnable)
Simply casts a method reference, which takes no parameters and returns void, to a
Consumer. |
static <T,U> java.util.function.Consumer<T> |
inverseConsumer(java.util.function.BiConsumer<? super U,? super T> biConsumer,
U value)
As in the
consumer(BiConsumer, Object) method, builds a consumer from a passed BiConsumer,
which can be very useful in the common situation where you are streaming through a collection elements, and have
a method to call that takes two parameters. |
static <T,U> java.util.function.Consumer<T> |
mapAndConsume(java.util.function.Function<? super T,? extends U> function,
java.util.function.Consumer<? super U> consumer)
Applies a
Function to a target element, before passing its result to a Consumer. |
static <T,U> java.util.function.Consumer<T> |
setter(java.util.function.BiConsumer<? super T,? super U> consumer,
java.util.function.Function<T,U> function)
This method is a variation of the
consumer(...) methods that has some special properties. |
public static <T> java.util.function.Consumer<T> consumer(java.util.function.Consumer<T> consumer)
Consumer. This could be useful in a situation where methods of the Consumer interface are to
be called on a method reference. In the following example, assume that methodOne() and
methodTwo() are methods in the current class, and both take a single parameter of type Widget:
Collection<Widget> widgets = ...
widgets.forEach(ConsumerUtils.consumer(this::methodOne)
.andThen(this::methodTwo));
Or, with static imports:
widgets.forEach(consumer(this::methodOne)
.andThen(this::methodTwo));
The Consumer.andThen() method can only be called on the method reference because of the cast.T - The type of the single parameter to the Consumer.consumer - A method reference to be cast to a Consumer.public static <T> java.util.function.Consumer<T> consumer(java.lang.Runnable runnable)
Consumer. This
could be useful in a situation where you have a method that takes no parameters, and has no return value, which
you would like to call in a stream, for example, in the Stream.forEach(...) method. In the following
example, assume that processWidget() and saveWidget both take a single
Widget parameter and have no return value, and logCurrentState() takes no parameter and
has no return value:
Collection<Widget> widgets = ...
widgets.forEach(ConsumerUtils.consumer(this::processWidget)
.andThen(ConsumerUtils.consumer(this::logCurrentState))
.andThen(this::saveWidget));
Or, with static imports:
widgets.forEach(consumer(this::processWidget)
.andThen(consumer(this::logCurrentState))
.andThen(this::saveWidget));
Admittedly, the fact that we are using forEach(...) here, using object state for the logging, and
not returning any values, makes this code imperative, and not functional. However, casting a
Runnable to a Consumer does come in handy at times.
Note that this method can also be used to cast a Supplier method reference to a
Consumer, that is a reference to a method that takes no parameters, and returns an object of any
type.
T - The type of the single parameter to the Consumer.runnable - A method reference taking no parameters and having a return value of any type, including no
return value, to be cast to a Consumer.public static <T,U> java.util.function.Consumer<T> consumer(java.util.function.BiConsumer<? super T,? super U> biConsumer,
U value)
BiConsumer, which can be very useful in the common situation where
you are streaming through a collection of elements, and have a method to call that takes two parameters - the
first one being the element on which you are streaming, and the second being some constant value that will be
passed to all invocations. This would typically be called from within the Collection.forEach(...)
or Stream.forEach(...) method. Another example of a method that requires a Consumer is
the Optional.ifPresent(...) method. The following is a contrived example, but it illustrates the use
of the method. Assume we have a collection of persistent entities that we have manipulated somehow, and now they
need to be saved to a database. Also assume the WidgetRepository.saveWidget() method takes a
Widget as the first parameter, and a String projectId as a second parameter:
private void saveWidgets(Collection<Widget> widgets, String projectId) {
widgets.forEach(ConsumerUtils.consumer(widgetRepository::saveWidget, projectId));
}
private void saveWidget(Widget widget, String projectId) {
...
}
Or, with static imports:
widgets.forEach(consumer(widgetRepository::saveWidget, projectId));
In this example, we have each widget to be saved being passed to the save method, along with a projectId, which
remains constant for every call.
One note about using the Java Consumer interface, as it says in the Javadoc documentation for it,
"Unlike most other functional interfaces, Consumer is expected to operate via side-effects."
T - The target type of the first parameter to the passed biConsumer.U - The type of the constant value to be passed as the second parameter to each invocation of
biConsumer.biConsumer - A method reference which is a BiConsumer, taking two parameters - the first of type <T>,
and the second of type <U>, either of which can be any type. The method reference will be
converted by this method to a Consumer, taking a single parameter of type <T>. Behind the
scenes, this BiConsumer will be called, passing the constant value to each invocation as the
second parameter.value - A constant value, in that it will be passed to every invocation of the passed biConsumer as the
second parameter to it, and will have the same value for each of them.public static <T,U> java.util.function.Consumer<T> inverseConsumer(java.util.function.BiConsumer<? super U,? super T> biConsumer,
U value)
consumer(BiConsumer, Object) method, builds a consumer from a passed BiConsumer,
which can be very useful in the common situation where you are streaming through a collection elements, and have
a method to call that takes two parameters. In the BiConsumer passed to this method, the parameters
are basically the same as in consumer(BiConsumer, Object), but in the inverse order. Here, the first
parameter is a constant value that will be passed to all invocations of the method, and the second parameter is
the element on which you are streaming. This would typically be called from within the Collection.forEach(...)
or Stream.forEach(...) method. Another example of a method that requires a Consumer
is the Optional.ifPresent(...) method. The following is a contrived example, but it illustrates the
use of the method. Assume we have a collection of persistent entities that we have manipulated somehow, and now
they need to be saved to a database. Also assume the WidgetRepository.saveWidget() method takes a
String projectId as the first parameter, and a Widget as the second parameter:
private void saveWidgets(Collection<Widget> widgets, String projectId) {
widgets.forEach(ConsumerUtils.inverseConsumer(widgetRepository::saveWidget, projectId));
}
private void saveWidget(String projectId, Widget widget) {
...
}
Or, with static imports:
widgets.forEach(inverseConsumer(widgetRepository::saveWidget, projectId));
This example looks almost exactly the same as the one in consumer(BiConsumer, Object), but the difference
is that the order of the parameters in the passed BiConsumer method reference are reversed. So the
parameters to the widgetRepository.saveWidget(...) method would be projectId, and then the
widget as the second parameter.
One note about using the Java Consumer interface, as it says in the Javadoc documentation for it,
"Unlike most other functional interfaces, Consumer is expected to operate via side-effects."
T - The target type of the second parameter to the passed biConsumer.U - The type of the constant value to be passed as the first parameter to each invocation of
biConsumer.biConsumer - A method reference which is a BiConsumer, taking two parameters - the first of type <U>,
and the second of type <T>, either of which can be any type. The method reference will be
converted by this method to a Consumer, taking a single parameter of type <T>. Behind the
scenes, this BiConsumer will be called, passing the constant value to each invocation as the
first parameter.value - A constant value, in that it will be passed to every invocation of the passed biConsumer as the
first parameter to it, and will have the same value for each of them.public static <T,U> java.util.function.Consumer<T> setter(java.util.function.BiConsumer<? super T,? super U> consumer,
java.util.function.Function<T,U> function)
consumer(...) methods that has some special properties. First, it
is assumed that a setter method is being called on the target element, so there is a null check to make sure that
it is an object instance. If not, the Consumer built by this method simply returns. Second, it takes
a function that, given the target element, it returns the value to be passed to the setter. This means that any
of the methods of MapperUtils are fair game to be used to build that function. For example, suppose we
want to write a method that, given a collection of Widget instances, it will build and set a
description for each of them. We could use this method to help accomplish that in the following contrived example:
private void buildWidgetDescriptions(Collection<Widget> widgets) {
String productLine = formatProductLine();
widgets.forEach(ConsumerUtils.setter(Widget::setDescription, MapperUtils.mapper(this::buildDescription, productLine)));
}
private String buildDescription(Widget widget, String productLine) {
...
}
Or, with static imports:
widgets.forEach(setter(Widget::setDescription, mapper(this::buildDescription, productLine)));
T - The type of the target input element.U - The type of the parameter to be passed to the setter method.consumer - A setter method reference from the class of the target element. It is a BiConsumer because the
first parameter will be the element itself, and the second parameter is the value to be set on
it.function - An extractor function that, given the target element, returns the value to be set.public static <T,U> java.util.function.Consumer<T> mapAndConsume(java.util.function.Function<? super T,? extends U> function,
java.util.function.Consumer<? super U> consumer)
Function to a target element, before passing its result to a Consumer. For
example, let's say that we have a collection of order line items, and we want to call a validation method to make
sure that the current customer is able to order items from the product type of the current line item:
private void validateLineItems(Collection<OrderLineItem> lineItems, String customerId) {
lineItems.forEach(ConsumerUtils.mapAndConsume(OrderLineItem::getProductType, ConsumerUtils.consumer(this::validateProductType, customerId)));
}
private String validateProductType(ProductType productType, String customerId) {
...
}
Or, with static imports:
lineItems.forEach(mapAndConsume(OrderLineItem::getProductType, consumer(this::validateProductType, customerId)));
Note that the same thing could be done like this:
lineItems.stream()
.map(OrderLineItem::getProductType)
.forEach(consumer(this::validateProductType, customerId));
Which of the above is more concise and readable is up to the individual developer, but this method provides an
alternative way of accomplishing the above validation.T - The type of the target input element.U - The type of the result of a Function, which will be passed to a Consumer.function - A Function to be applied to a target element.consumer - A Consumer to be applied to the result of a Function.