27

I read many examples about how to easily define a lambda in Java 8. This lambda takes always one parameter like f1:

Function<Integer,Integer> f1 = (x) -> Math.pow(x,2);

Of course, you can extend the body like f2:

Function<Integer,Integer> f2 = (x) -> {if (x < 0)  return 0;
                                       else return Math.pow(x,2);};

But I cannot find a way to define a lambda with a variable number of paramters like f3:

Function<Integer,Integer,Integer> f3 = (x,y) -> {return x + y};

or without parameter like f4:

Function<Double> f4 = () -> {return Math.random()};

I am almost sure that you can define own functional interface (i.e., create a new file commonly) to develop f3 and f4, but Is there some way to easily define them?

Naive Developer
  • 700
  • 1
  • 9
  • 17

3 Answers3

37
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

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • 1
    Or, if all parameters are the same type, create a varargs version: `interface NAryFunction { R apply(T... t); }` – Andreas Aug 09 '18 at 20:00
  • 4
    @Andreas I did not suggest that on purpose, I haven't found myself in a need of one, ever, so was not sure. thank you though – Eugene Aug 09 '18 at 20:01
8

I am almost sure that you can define own functional interface (i.e., create a new file commonly) to develop f3 and f4, but Is there some way to easily define them?

In addition to the Eugene answer, I would add that :

Function<Integer,Integer,Integer> f3 = (x,y) -> {return x + y};

may be considered as BiFunction<Integer,Integer,Integer> or simply BinaryOperator<Integer>. Note that you perform arithmetical computations with the Integers in the lambda body. These produce unboxing and boxing operations : Integer->int->Integer. So in this use case you are encouraged to use a specialized functional interface that prevents that : IntBinaryOperator which the functional signature is (int, int)-> int that is itself a specialization of BinaryOperator<T> a subclass of BiFunction<T,T,T>

In the same logic of sparing autoboxing operations : Function<Integer,Integer> f2 should be IntFunction f2 and Supplier<Double> f4 should be DoubleSupplier f4.

Note also that specifying a specific number of argument makes sense as it is straight usable in a lambda body but specifying something like a var-args is possible but generally harder to exploit.

For example you could declare this interface :

@FunctionalInterface
public interface VargsFunction<T,R> {
    @SuppressWarnings("unchecked")
    R apply(T...  t);
}

But harder to use without delegating to a method that accepts a var-args :

VargsFunction<Integer, Integer> f = varg-> call(varg);

Integer call(Integer... varg) {
    ...
}
davidxxx
  • 125,838
  • 23
  • 214
  • 215
5

A function that takes two arguments is a BiFunction:

BiFunction<Integer, Integer, Integer> f3 = (x, y) -> x + y;

A function that takes no arguments is a Supplier:

Supplier<Double> f4 = () -> Math.random();

or equivalently:

Supplier<Double> f4 = Math::random;
Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135