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

JavaC#LambdaJava 8Java Stream

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

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.

Solution 3 - Java

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.

Solution 4 - Java

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

An object can contain any number of other objects. The Streams API is designed to stream just one object at a time, and if you need more you would wrap these in an object which holds them all.

e.g.

Map<String, Long> map = new HashMap<>();
// each entry has a key and a value as Map.Entry<String, Long>
Map<Long, String> revMap = map.entrySet().stream()
            .collect(groupingBy(Entry::getValue(), HashMap::new, Entry::getKey));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMiguel GamboaView Question on Stackoverflow
Solution 1 - JavaLevView Answer on Stackoverflow
Solution 2 - JavaSimY4View Answer on Stackoverflow
Solution 3 - JavaMark LackeyView Answer on Stackoverflow
Solution 4 - JavaPeter LawreyView Answer on Stackoverflow