Java 8: Where is TriFunction (and kin) in java.util.function? Or what is the alternative?
As far as I know, there are only two kinds of functions, destructive and constructive.
While constructive function, as the name implies, constructs something, a destructive one destroys something, but not in the way you may think now.
For example, the function
Function<Integer,Integer> f = (x,y) -> x + y
is a constructive one.
As you need to construct something. In the example
you constructed the tuple (x,y). Constructive functions have the problem,
of being not able to handle infinite arguments. But the worst thing is, you
can't just leave an argument open. You can't just say "well, let x := 1" and try out
every y you may like to try. You have to construct every time the whole tuple with x := 1
. So if you like to see what the functions return for y := 1, y := 2, y := 3
you
have to write f(1,1) , f(1,2) , f(1,3)
.
In Java 8, constructive functions should be handled (most of the time) by using method references because there's not much advantage of using a constructive lambda function. They are a bit like static methods.
You can use them, but they have no real state.
The other type is the destructive one, it takes something and dismantles it as far as needed.
For example, the destructive function
Function<Integer, Function<Integer, Integer>> g = x -> (y -> x + y)
does the same as the function f
which was constructive. The benefits of a destructive function are, you
can handle now infinite arguments, which is especially convenient for streams, and you can just leave arguments open.
So if you again want to see what would the result be like if x := 1
and y := 1 , y := 2 , y := 3
, you can say h = g(1)
andh(1)
is the result for y := 1
, h(2)
for y := 2
and h(3)
for y := 3
.
So here you have a fixed state! That's quite dynamic and that's most of the time that what we want from a lambda.
Patterns like Factory are a lot easier if you can just put in a function which does the work for you.
Destructive ones are easily combined with each other. If the type is right you can just compose them as you like. Using that, you can easily define morphisms which make (with immutable values) testing a lot easier!
You can do that too with a constructive one, but destructive composition looks nicer and more like a list or a decorator, and the constructive one looks a lot like a tree. And things like backtracking
with constructive functions are just not nice. You can just save the partial functions of a destructive one (dynamic programming), and on "backtrack" just use the old destructive function. That makes code a lot smaller and better readable. With constructive functions you have more or less to remember all arguments, which can be a lot.
So why is there a need for BiFunction
should be more of question than why there is no TriFunction
?
First of all, a lot of time you just have a few values (less than 3) and need just a result, so a normal destructive function would not be needed at all, a constructive one would do fine. And there are things like monads which
really needs a constructive function. But aside from that, there are not really a lot of good reasons why there is a BiFunction
at all. Which doesn't mean it should be removed! I fight for my Monads until I die!
So if you have a lot of arguments, which you can't combine into a logical container class, and if you need the
function to be constructive, use a method reference. Otherwise try to use the new gained ability of destructive functions, you may find yourself doing a lot of things with a lot less code lines.
Function.Function of Java 8 with multiple parameters
Function<Integer,Integer,Integer> f3 = (x,y) -> {return x + y};
is actually a BiFunction<Integer,Integer,Integer>
and
Function<Double> f4 = () -> {return Math.random()};
is a Supplier<Double>
If you need more create your own, like TriFunction<Integer,Integer,Integer,Integer>
for example
identify build in functional interface
Nope. There's nothing in the java.util.function
package which applies to this.
If the function only had 2 arguments, e.g.
(name, age) -> ...
then you could use BiFunction
but there is no "TriFunction
".
A recursive lambda TriFunction
You are trying to use a technique called currying. The basic idea is that a function of two or more arguments f(x, y)
can be represented as a function that returns a function f(x)(y)
.
For example here's a "curried" function that adds 3 numbers:
public static Function<Integer, Function<Integer, Function<Integer, Integer>>>
sum3 = x -> y -> z -> x + y + z;
This style does not really suit Java because a key philosophy of the language is that names are meaningful. Creating anonymous functions goes against this idea.
In your own code, you should not use raw types such as Function
. If you don't know/care about the type, use a wildcard ?
:
public static Function<Integer, Function<Integer, Function<?,?>>> myPowerTriFunction;
What's the elegant way to replace following code in java 8?
You can try something like this:
@FunctionalInterface interface TriPredicate<A, B, C> {
boolean test (A a, B b, C c);
}
private BiPredicate<Class1, Class2> matchObjects = (obj1, obj2) -> {
TriPredicate<String, String, Boolean> matchProp = (propA, propX, cond) ->
propA == null && propX == null ||
(cond == null || cond) == Objects.equals(propA, propX);
return matchProp.test(obj1.propertyA, obj2.propertyX, obj1.propertyANot) &&
matchProp.test(obj1.propertyB, obj2.propertyY, null) &&
matchProp.test(obj1.propertyC, obj2.propertyZ, null) &&
matchProp.test(obj1.propertyD, obj2.propertyW, obj1.propertyDNot);
};
How can we have 2 parameters in java.util.function.Function lambda?
This is done using a BiFunction<T,U,R>
. Following is an example of a BiFunction
returning the character at the specified index of a String:
BiFunction<String, Integer, Character> charAtFunction = (string, index) -> string.charAt(index);
Parametrise a Runnable object at runtime
I suggest you change doSomething
to a Consumer
that accepts your parameters:
public void foo(ScheduledExecutorService execService) {
Consumer<YourParams> doSomething = (params) -> {
/*Code that I DON’T want to duplicate*/
/* small piece of code that I need to parametrise */
// use params
};
// after someDelayInSeconds doSomething.run() will be called
YourParams asyncParams = /* parameters for async execution */;
execService.schedule(() -> doSomething.accept(asyncParams), someDelayInSeconds, TimeUnit.SECONDS);
// this might or might not call doSomething.run()
bar(doSomething);
}
private void bar(Consumer<YourParams> doSomething) {
if (/* some conditions are met */) {doSomething.accept(otherParams);}
}
In the scheduled execution you then transform doSomething
into a Runnable
by passing the default parameters for asynchronous execution, while in bar()
you pass the alternative parameters of your choice directly.
What java8 syntax is this and where can i read more?
That's called an initializer block
that executes two methods get
.
That get
methods looks like take a String
and a BiConsumer
as input. Other than that not entirely sure what other syntax confuses u.
Related Topics
Annotation @Transactional. How to Rollback
Java - Delete Line from Text File by Overwriting While Reading It
Integer Arithmetic in Java with Char and Integer Literal
Throw Checked Exceptions from Mocks with Mockito
How to Write an Arraylist of Strings into a Text File
Why Does Autoreconnect=True Not Seem to Work
Generic Wildcard Types Should Not Be Used in Return Parameters
Why Static Fields Are Not Initialized in Time
What Java 8 Stream.Collect Equivalents Are Available in the Standard Kotlin Library
Can You Write Virtual Functions/Methods in Java
What Does Class<> Mean in Java
How Does the Spring @Responsebody Annotation Work
How to Sort Arraylist<Long> in Decreasing Order
Meaning of Delta or Epsilon Argument of Assertequals for Double Values
How to Encode Uri Parameter Values
Log4J Configuration via Jvm Argument(S)