Assume I have the following functional interface:
public interface TemperatureObserver { void react(BigDecimal t); }
and then in another class an already filled-in ArrayList
of objects of type TemperatureObserver
. Assuming that temp
is a BigDecimal
, I can invoke react
in a loop using:
observers.forEach(item -> item.react(temp));
My question: can I use a method reference for the code above?
The following does not work:
observers.forEach(TemperatureObserver::react);
The error message is telling me that
forEach
in the Arraylist observers
is not applicable to the type TemperatureObserver::react
TemperatureObserver
does not define a method react(TemperatureObserver)
Fair enough, as forEach
expects as an argument a Consumer<? super TemperatureObserver>
, and my interface, although functional, does not comply to Consumer
because of the different argument of react
(a BigDecimal
in my case).
So can this be solved, or it is a case in which a lambda does not have a corresponding method reference?
Java provides a new feature called method reference in Java 8. Method reference is used to refer method of functional interface. It is compact and easy form of lambda expression. Each time when you are using lambda expression to just referring a method, you can replace your lambda expression with method reference.
The forEach method was introduced in Java 8. It provides programmers a new, concise way of iterating over a collection. The forEach method performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception.
There are several types of a method reference in Java that are allowed in Java 8. Reference to some static methods: The static methods in a code can be referred to from a class. Reference to some instance method of particular objects: Reference to some instance method of an arbitrary object of any particular type.
The method references can only be used to replace a single method of the lambda expression. A code is more clear and short if one uses a lambda expression rather than using an anonymous class and one can use method reference rather than using a single function lambda expression to achieve the same.
There are three kinds of method references that can be used when a single value is available from the stream:
A parameter-less method of the streamed object.
class Observer { public void act() { // code here } } observers.forEach(Observer::act); observers.forEach(obs -> obs.act()); // equivalent lambda
The streamed object becomes the this
object of the method.
A static method with the streamed object as parameter.
class Other { public static void act(Observer o) { // code here } } observers.forEach(Other::act); observers.forEach(obs -> Other.act(obs)); // equivalent lambda
A non-static method with the streamed object as parameter.
class Other { void act(Observer o); } Other other = new Other(); observers.forEach(other::act); observers.forEach(obs -> other.act(obs)); // equivalent lambda
There is also a constructor reference, but that is not really relevant to this question.
Since you have an external value temp
, and you want to use a method reference, you can do the third option:
class Temp { private final BigDecimal temp; public Temp(BigDecimal temp) { this.temp = temp; } public void apply(TemperatureObserver observer) { observer.react(this.temp); } } Temp tempObj = new Temp(temp); observers.forEach(tempObj::apply);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With