It's possible if you define such a functional interface with multiple type parameters. There is no such built in type. (There are a few limited types with multiple parameters.)
@FunctionalInterface
interface Function6<One, Two, Three, Four, Five, Six> {
public Six apply(One one, Two two, Three three, Four four, Five five);
}
public static void main(String[] args) throws Exception {
Function6<String, Integer, Double, Void, List<Float>, Character> func = (a, b, c, d, e) -> 'z';
}
I've called it Function6 here. The name is at your discretion, just try not to clash with existing names in the Java libraries.
There's also no way to define a variable number of type parameters, if that's what you were asking about.
Some languages, like Scala, define a number of built in such types, with 1, 2, 3, 4, 5, 6, etc. type parameters.
Answer from Sotirios Delimanolis on Stack OverflowIt's possible if you define such a functional interface with multiple type parameters. There is no such built in type. (There are a few limited types with multiple parameters.)
@FunctionalInterface
interface Function6<One, Two, Three, Four, Five, Six> {
public Six apply(One one, Two two, Three three, Four four, Five five);
}
public static void main(String[] args) throws Exception {
Function6<String, Integer, Double, Void, List<Float>, Character> func = (a, b, c, d, e) -> 'z';
}
I've called it Function6 here. The name is at your discretion, just try not to clash with existing names in the Java libraries.
There's also no way to define a variable number of type parameters, if that's what you were asking about.
Some languages, like Scala, define a number of built in such types, with 1, 2, 3, 4, 5, 6, etc. type parameters.
For something with 2 parameters, you could use BiFunction. If you need more, you can define your own function interface, like so:
@FunctionalInterface
public interface FourParameterFunction<T, U, V, W, R> {
public R apply(T t, U u, V v, W w);
}
If there is more than one parameter, you need to put parentheses around the argument list, like so:
FourParameterFunction<String, Integer, Double, Person, String> myLambda = (a, b, c, d) -> {
// do something
return "done something";
};
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
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) {
...
}
The solution depends on the answer to the question - are all the parameters going to be the same type and if so will each be treated the same?
If the parameters are not the same type or more importantly are not going to be treated the same then you should use method overloading:
public class MyClass
{
public void doSomething(int i)
{
...
}
public void doSomething(int i, String s)
{
...
}
public void doSomething(int i, String s, boolean b)
{
...
}
}
If however each parameter is the same type and will be treated in the same way then you can use the variable args feature in Java:
public MyClass
{
public void doSomething(int... integers)
{
for (int i : integers)
{
...
}
}
}
Obviously when using variable args you can access each arg by its index but I would advise against this as in most cases it hints at a problem in your design. Likewise, if you find yourself doing type checks as you iterate over the arguments then your design needs a review.
Suppose you have void method that prints many objects;
public static void print( Object... values){
for(Object c : values){
System.out.println(c);
}
}
Above example I used vararge as an argument that accepts values from 0 to N.
From comments: What if 2 strings and 5 integers ??
Answer:
print("string1","string2",1,2,3,4,5);
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);
Try :
BiFunction<Integer, Integer, String> lambda = (a, b) -> ("Given values are " + a + ", " + b);
What about passing the function as a parameter to your useMyMethod function?
If you are using Java < 8:
public interface A {
void myMethod();
}
public interface B {
void myMethod();
}
public void useMyMethod(Callable<Void> myMethod) {
try {
myMethod.call();
} catch(Exception e) {
// handle exception of callable interface
}
}
//Use
public void test() {
interfaceA a = new ClassImplementingA();
useMyMethod(new Callable<Void>() {
public call() {
a.myMethod();
return null;
}
});
interfaceB b = new ClassImplementingB();
useMyMethod(new Callable<Void>() {
public call() {
b.myMethod();
return null;
}
});
}
For Java >= 8, you could use Lambda Expressions:
public interface IMyMethod {
void myMethod();
}
public void useMyMethod(IMyMethod theMethod) {
theMethod.myMethod();
}
//Use
public void test() {
interfaceA a = new ClassImplementingA();
useMyMethod(() -> a.myMethod());
interfaceB b = new ClassImplementingB();
useMyMethod(() -> b.myMethod());
}
Try using Adapter design pattern.
Or, if it's possible, add some base interface:
public interface Base {
void myMethod();
}
public interface A extends Base {}
public interface B extends Base {}
...
public void useMyMethod(Base b) {
b.myMethod()
}
Also, you can use something similar to this
If you need to do "something" for only Integer and Double types, and need to add instances of that type, and the body of the method is more complicated than just adding the parameters: use two overloads, and delegate to a private method:
static Integer on(Integer a, Integer b) {
return on(a, b, Integer::sum);
}
static Double on(Double a, Double b) {
return on(a, b, Double::sum);
}
private static <T> T on(T a, T b, BinaryOperator<T> sum) {
// ... Something, using `sum.apply` to add things.
}
Callers (outside this class) can only invoke the Integer/Double overloads here. Generics won't directly allow you to restrict to specific types; all you can do is to restrict the visibility of the generic method.
You could solve it like this:
static Double on(Double a, Double b) {
return a+b;
}
static Integer on(Integer a, Integer b) {
return on(a.doubleValue(), b.doubleValue()).intValue();
}
static void test() {
System.out.println(on(1.0, 2.0).getClass());
System.out.println(on(1, 2).getClass());
}
This will not work however if you try to call this with two primitives where one is an int and the other is a double:
static void test2() {
System.out.println(on(1, 2.0).getClass()); // this doesn't compile
}