Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is the Java 8 Consumer with more than one argument?

Such as in .Net, which provides several implementations of the Action delegate (equivalent to Java Consumer functional interface) with different number and type of arguments, I was expecting that Java 8 provides some way of specifying a Consumer with more than one argument of different types.

I know that in Java we cannot define different types with the same name that just differ in the generic type parameters, but there would be nice fluent alternatives to provide a multi-argument Consumer.

Is there any easy way to do it, which does not require defining a new functional interface?

like image 273
Miguel Gamboa Avatar asked Jul 16 '14 11:07

Miguel Gamboa


3 Answers

For 3 and more arguments you could use curried(http://en.wikipedia.org/wiki/Currying) functions with last consumer:

Function<Double, Function<Integer, Consumer<String>>> f = d -> i -> s -> {
            System.out.println("" + d+ ";" + i+ ";" + s); 
        };
f.apply(1.0).apply(2).accept("s");

Output is:

1.0;2;s

It's enough to have a function of one argument to express function of any number of arguments: https://en.wikipedia.org/wiki/Currying#Lambda_calculi

like image 152
Lev Avatar answered Oct 16 '22 23:10

Lev


By default you're limited with only java.util.function.Consumer and java.util.function.BiConsumer. They are sufficient for current java streaming API. But you can create your own functional interfaces that will receive as many arguments as you like and use it in your own custom APIs.

like image 36
SimY4 Avatar answered Oct 16 '22 23:10

SimY4


It's pretty easy to define Functional Interfaces for yourself. In the project I am currently working on, I have found several occasions where passing a method as an argument has allowed me to keep my code nice and DRY. Here are some functional interfaces I've defined:

@FunctionalInterface
public interface CheckedVoidFunction {
    void apply() throws Exception;
}

@FunctionalInterface
public interface VoidFunction {
    void apply();
}

@FunctionalInterface
public interface SetCategoryMethod {
    void accept(ObservableList<IRegionWithText> list, Document document, String pattern);
}

Here are a method that accepts these kinds of arguments:

private void loadAnnotations(String annotationType, VoidFunction afterLoadFunction, List<Path> documentPaths) {

And here is where I call these methods with different methods as arguments:

loadAnnotations(DocumentReader.REDACTION_ANNOTATION_TYPE, this::afterLoadRedactions, documentPaths);
loadAnnotations(DocumentReader.HIGHLIGHT_ANNOTATION_TYPE, this::afterLoadHighlights, documentPaths);

There may be better ways to do this, but I thought I'd share what has been useful for me.

like image 10
Mark Lackey Avatar answered Oct 17 '22 00:10

Mark Lackey