Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Func-Programming in Java. Method-ref doesn't match the Function apply signature yet successfully runs

I'm currently reading Functional Programming in Java by Venkat Subramaniam and so far its been a great read.

There is a particular example however that is causing me some confusion. In the code example below there is a method called setFilters(final Function<Color,Color>... filters).

This expects a list implementing the Function interface. In the code setFilters is called using method references ... camera.setFilters(Color::lighter, Color::darker);.

This is confusing because the Color class does not implement the Function interface and nor does it have a method that matches the R apply(T t); signature.

Have I missed something obvious here? Can someone please explain how Color::darker etc can be passed into a parameter that expects Function<Color,Color>

Here is the full code example:

package designing.fpij;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.util.stream.Stream;
import java.util.function.Function;
import java.awt.Color;
import java.util.function.Consumer;

@SuppressWarnings("unchecked")
public class Camera {  
  private Function<Color, Color> filter;


  public Color capture(final Color inputColor) {
    final Color processedColor = filter.apply(inputColor);
    return processedColor;
  }

  public void setFilters(final Function<Color, Color>... filters) {
    filter =
            Stream.of(filters).
                    reduce((after, before) -> filter.compose(before)).orElse(color -> color);
  }
  public Camera() {
    setFilters();
  }

  public static void main(final String[] args) {
    final Camera camera = new Camera();
    final Consumer<String> printCaptured = (filterInfo) ->
            System.out.println(String.format("with %s: %s", filterInfo, camera.capture(new Color(200, 100, 150))));

    System.out.println("//" + "START:NOFILTER_OUTPUT");
    printCaptured.accept("no filter");
    System.out.println("//" + "END:NOFILTER_OUTPUT");

    System.out.println("//" + "START:BOTH_OUTPUT");
    camera.setFilters(Color::brighter, Color::darker);
    printCaptured.accept("brighter & darker filter");
    System.out.println("//" + "END:BOTH_OUTPUT");

  }

}
like image 662
tezza Avatar asked Jun 30 '26 21:06

tezza


1 Answers

Calling

camera.setFilters(Color::darker);

is the equivalent of

setFilters(new Function<Color, Color>() {
    @Override
    public Color apply(Color color) {
        return color.darker();
    }
});

(if you were using pre-Java-8 anonymous inner classes). You can see when you add all the boilerplate that Color does not need to be a FunctionalInterface or implement Function - in the longer form you would be wrapping a call to this method inside a Function.

Simplifying this call to a lambda gives

setFilters((Function<Color, Color>) color -> color.darker());

or even shorter:

setFilters(color -> color.darker());

which ultimately can be simplified into your method reference:

setFilters(Color::darker);
like image 103
Trisha Avatar answered Jul 02 '26 10:07

Trisha



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!