Let me remind you: arity (English arity) is the number of parameters of the function. Accordingly, multi-ary (this word can be written together or separately) functions are functions with several parameters. Java 8 introduced functions with one and two input parameters. And what if there are more parameters?
When you need a lot of input parameters
In Java, there is Function <X, R> and BiFunction <X, Y, R>, where X and Y are the types of the input parameters and R is the type of the output parameter. But functions with three and a large number of input parameters must be determined by oneself. Where does this injustice come from? Why is it possible to define a method in a class with any number of parameters, and functions with three or more parameters need to be specifically defined? But if necessary - try to determine. But how? Surely you have heard about currying - a method of converting a function with N parameters into a function with N - 1 parameters. And probably this is the first thing that many will immediately think of: I need to curry my multiparameter (multiarn) function! But how to convert your particular function? For example, you have a function
You guessed how to bring it to mind
Or is it hard? How is it done, this very currying? It seems recently came across an article on this topic ... I will not torment you further. Do not be scared. Java 8 does it for you. For example, to further define functions with three input parameters:
you need to first define the interface once:
@FunctionalInterfacepublicinterfaceFunction3Arity<A, B, C, R> { R apply(A a, B b, C c); }
After that, you can define specific variants of ternary (three-ary) functions. For example, like this:
private static Function3Arity<Integer, String, Integer, String> f3 = (a, op, b) ->{return"" + a + op + b + "=" + (a+b);};
Check how it works:
@TestpublicvoidtestFunction3Arity(){ String result = f3.apply(2, "+", 3); assertEquals("2+3=5", result); }
You must define the corresponding interfaces for each used arity N = 3,4, ... And everything is good, it’s only bad that it is simply impossible to come to this decision in a rational way. (If you, like me, are not an expert in functional programming). I mean the ability of the apply method to perceive and correctly interpret an arbitrary number of parameters. This is not written in the documentation. And it is not written whether it can be done in any other way. And when I had this task before me, I hoped to find something similar in the specification of the Function class or the package containing it. For example, here or here .
When you need a lot of output parameters
We looked at an example where there were many input parameters. And what if we have a lot of output parameters? As you know, Java allows returning to return only one primitive element or object. And I would like to be able to distinguish between input and output parameters at the level of the function signature. Those. have type signatures:
Unfortunately, to do this directly will not work. Output parameters need to be structured somehow. To do this, you can create a temporary object or write parameters to the list (List <?>). The first method is heavy and the second is unpleasant for the loss of static control over the types of output parameters, if these types are different. From my point of view, it is more elegant to use <TupleN <X1, X2, ..Xn>. For example, the class Tuple2 looks like this:
publicclassTuple2<A, B> { publicfinal A a1; publicfinal B a2; publicTuple2(A t, B u){ a1 = Objects.requireNonNull(t); a2 = Objects.requireNonNull(u); } @Overridepublicbooleanequals(Object o){…} @OverridepublicinthashCode(){…} }
Using this class, a function with three input and two output parameters can be defined like this:
private static Function3Arity<Integer, String, Integer, Tuple2<Integer, String>> f3And2 = (a, op, b) ->{ int intValue = a + b; String sValue = "" + a + op + b + "=" + (a+b); returnnew Tuple2<>(intValue, sValue); };
If your function has 3 or more input parameters (s), you need to define a new N-ary interface and use it to subsequently determine specific functions.
If your function has 2 or more output parameters (s), define the class TupleN and package the parameters into it before exiting the function with return.
You'll find example code in my GitHub project here . Illustration: geralt