Gangmax Blog

自由之思想,独立之精神

Java Lambda Type Inference

| Comments

I see code like this:

Service.java
1
2
3
4
5
6
7
8
9
@Override
public void log(Request request) {
    // ...
}

@Override
public void submit(Request request) {
    Utils.submit(request, request -> log(request));
}

Here is the code in “Utils.java”:

Utils.java
1
2
3
4
public static void submit(Request request, Consumer<Request> comsumer) {
    // Do something.
    comsumer.accept(request);
}

“request -> log(request)” is a lambda expression, but how does it become a “Consumer”?

The answer is ”Java Lambda Type Inference”. In short it means:

  1. One lambda expression may map to different functional interface types depending on the context.

  2. The compiler infers the type of a lambda expression.

  3. Conceptually ”Functional interface” is an interface has exact one abstract method.

  4. The process of inferring the type of a lambda expression is called target typing. The compiler uses the following rules to determine whether a lambda expression is assignable to its target type:

    1. It must be a functional interface.

    2. The parameters of lambda expression must match the abstract method in functional interface.

    3. The return type from the lambda expression is compatible with the return type from the abstract method in functional interface.

    4. The checked exceptions thrown from the lambda expression must be compatible with the declared throws clause of the abstract method in functional interface.

The code below is an example of the Lambda type inference:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Main {
  public static void main(String[] argv) {
    Processor stringProcessor = (String str) -> str.length();
    SecondProcessor secondProcessor = (String str) -> str.length();
    //from w  w  w. ja  va 2s . c  o  m
    //stringProcessor = secondProcessor; //compile error
    String name = "Java Lambda";
    int length = stringProcessor.getStringLength(name);
    System.out.println(length);

  }
}

@FunctionalInterface
interface Processor {
  int getStringLength(String str);
}

@FunctionalInterface
interface SecondProcessor {
  int noName(String str);
}

One more thing about “@FunctionalInterface” (from here) is that:

The compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a FunctionalInterface annotation is present on the interface declaration.

So the functionality of the “@FunctionalInterface” annotation is to generate compiling error if the annotated interface is not a functional interface and improve readability, not a grammar prerequiste of a functional interface.

Comments