0

How can I create an array or List of functions in Java 17 (or similar)?

Expected hypothetical usage:

    var myListOfFunctions = List.of(this::myFunction, MyClass::someOtherFunction);

I get the following error:

Object is not a functional interface

I intend to stream the functions and pass them the same data.

Halil Ozel
  • 2,482
  • 3
  • 17
  • 32
Ahmed Tawfik
  • 1,159
  • 1
  • 8
  • 13
  • Do the functions all have the same signature? – Unmitigated Feb 20 '23 at 19:12
  • Yes, naturally. – Ahmed Tawfik Feb 20 '23 at 19:21
  • 3
    The problem is that there's not enough type information to infer the parameterization of `List`, so it defaults to `List`. Either replace `var` with the actual type (e.g., `List>`) or use a type witness (e.g., `List.>of(...)`). Replace `Function` with the actual type you're using. – Slaw Feb 20 '23 at 20:32
  • I didn't know about type witnesses (the List.) before @NoDataFound's answer. Thank you for providing extra context. – Ahmed Tawfik Feb 20 '23 at 21:14
  • 2
    The problem is similar to the one answered here: https://stackoverflow.com/questions/49578553/why-cant-the-var-keyword-in-java-be-assigned-a-lambda-expression/49581723#49581723. The issue is not `var` per se, but that lambdas and method references do not have a standalone type -- they need to get their type from context. This could be an assignment target or cast, but you need _something_ that says what functional interface you want. – Brian Goetz Feb 25 '23 at 17:56

2 Answers2

5

First, create a functional interface that represents the common signature of all the functions. Note: there may be an interface from the java.util.function package that can be used to represent the signature, so it may not be necessary to create a new interface.

// for example
@FunctionalInterface
interface MyFunction {
    int f(int a, int b); // this must match the signature of each function
}

Then, create a List of that type.

List<MyFunction> functions = List.of(this::myFunction, MyClass::someOtherFunction);
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • Thanks, this seems to be a more complete, suitable for a wider variety of visitors seeking an answer to this question. – Ahmed Tawfik Feb 20 '23 at 21:13
2

You have to help Java a little for this one:

var myListOfFunctions = List.<Function<String,Integer>> of(this::myFunction, MyClass::someOtherFunction);

This would generate a List<Function<String, Integer>>.

NoDataFound
  • 11,381
  • 33
  • 59
  • 6
    Or just don't use var... – Michael Feb 20 '23 at 19:25
  • Depends on the whim of the compiler: I'm pretty sure that JDT (Eclipse) will fail here. – NoDataFound Feb 20 '23 at 20:37
  • Thanks. This has worked. It was a simple one input, one output function signature, so this suits my needs best. – Ahmed Tawfik Feb 20 '23 at 21:11
  • 1
    @Michael The problem is not `var`, but that method references and lambdas do not have a _standalone type_. There are many ways to provide a suitable target type for them, some compatible with `var`, but you have to provide _some_ type information so the compiler knows what functional interface you want the lambda/mref to be typed as. – Brian Goetz Feb 25 '23 at 17:57
  • 1
    @NoDataFound No, it does not depend on the whim of the compiler. The behavior is entirely well specified, and any conformant compiler will get the same answer. – Brian Goetz Feb 25 '23 at 17:58
  • @BrianGoetz You know better than anyone that it was designed to make code more expressive. If you need a type witness, which a lot of developers don't even know exists as a feature, it's not really achieving that goal. "Problem" might be going too far, but that was your choice of words, not mine. – Michael Feb 25 '23 at 18:01
  • @BrianGoetz this issue https://github.com/eclipse-jdt/eclipse.jdt.core/issues/494 is one of those I call "whim": you would have to tell the compiler (jdt) the exact type you expect or it wont compile. – NoDataFound Feb 25 '23 at 20:45
  • 1
    You can call it "whim", but it's not. It's just a bug in the compiler implementation, which should be fixed. – Brian Goetz Feb 25 '23 at 22:13