Java 之 Functional Interfaces, Lambda Expressions

发布时间 2023-03-22 21:13:06作者: UPeRVv

简述

We propose extending the Java Language to support compact lambda expressions (otherwise known as closures or anonymous methods.) Additionally, we will extend the language to support a conversion known as "SAM conversion" to allow lambda expressions to be used where a single-abstract-method interface or class is expected, enabling forward compatibility of existing libraries.

We propose extending the semantics of interfaces in the Java Language to support virtual extension methods, whereby an interface can nominate a static default method to stand in for the implementation of an interface method in the event that an implementation class does not provide an implementation of the extension method. This enables interfaces to be augmented with new methods "after the fact" without breaking existing implementation classes.

—— JSR 335, short description

JSR 335 将 Lambda 表达式引入 Java 语言,包含 Lambda Expressions, SAM Conversion, Method References, Default methods (Virtual Extension Methods) 等特性。

Functional interfaces

A functional interface is an interface that is not declared sealed and has just one abstract method (aside from the methods of Object), and thus represents a single function contract.

-- JLS §9.8

Functional Interface, 也称 SAM 类型(即 Single Abstract Method),是指只有一个抽象方法的接口(Object 的方法不做计数)。

Functional Interface 使用上是自然的,不需要做特别操作。而作为 API 作者,可使用 @FunctionalInterface 注解,告诉编译器检查这个接口,保证该接口只能包含一个抽象方法,否则就会编译出错。

设计上没有采用 arrow type (structural function type),开发组有几个理由,一来不想向全是 nominal type 的 Java Type System 添加一个 structural type,这会带来更多的复杂度,也会带来更多 API 风格的分歧,二来语法上要有更多的设计,以避开可能出现的问题。Use what you know.

Java 8 之前就有的接口

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.util.Comparator
  • java.io.FileFilter
  • ...

Java 8 添加的接口

  • java.util.function
    • Function<T, R>, BiFunction<T, U, R>
    • Predicate<T>, BiPredicate<T, U>
    • Consumer<T>, BiConsumer<T, U>
    • Supplier<T>
    • UnaryOperator<T>
    • BinaryOperator<T>
  • ...

Lambda expressions

A lambda expression is like a method: it provides a list of formal parameters and a body - an expression or block - expressed in terms of those parameters.

 

Evaluation of a lambda expression produces an instance of a functional interface. Lambda expression evaluation does not cause the execution of the expression's body; instead, this may occur at a later time when an appropriate method of the functional interface is invoked.

-- JLS §15.27

Java 8 Syntax
LambdaExpression:
  LambdaParameters -> LambdaBody

LambdaParameters:
  Identifier
  ( [FormalParameterList] )
  ( InferredFormalParameterList )

LambdaBody:
  Expression
  Block

InferredFormalParameterList:
  Identifier {, Identifier}

FormalParameterList:
  ReceiverParameter
  FormalParameters , LastFormalParameter
  LastFormalParameter

FormalParameters:
  FormalParameter {, FormalParameter}
  ReceiverParameter {, FormalParameter}

FormalParameter:
  {VariableModifier} UnannType VariableDeclaratorId

LastFormalParameter:
  {VariableModifier} UnannType {Annotation} ... VariableDeclaratorId
  FormalParameter

VariableModifier:
  (one of)
  Annotation final

VariableDeclaratorId:
  Identifier [Dims]

Dims:
  {Annotation} [ ] {{Annotation} [ ]}

Target typing

A lambda expression's type is inferred from the surrounding context.

The following contexts have target types:

  • Variable declarations
  • Assignments
  • Return statements
  • Array initializers
  • Method or constructor arguments
  • Lambda expression bodies
  • Conditional expressions (?:)
  • Cast expressions

Lexical scoping & Variable capture

Lambda expressions are lexically scoped, meaning that names in the body are interpreted just as they are in the enclosing environment (with the addition of new names for the lambda expression's formal parameters).

Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be final or effectively final.

Any local variable used but not declared in a lambda body must be definitely assigned before the lambda body.

Method references

There are several different kinds of method references, each with slightly different syntax:

  • A static method (ClassName::methName)
  • An instance method of a particular object (instanceRef::methName)
  • super method of a particular object (super::methName)
  • An instance method of an arbitrary object of a particular type (ClassName::methName)
  • A class constructor reference (ClassName::new)
  • An array constructor reference (TypeName[]::new)

Default and static interface methods

 

A Peek Under the Hood

 

参考

  1. Project Lambda - <https://openjdk.org/projects/lambda/>
  2. JSR 335: Lambda Expressions - <https://www.jcp.org/en/jsr/detail?id=335>
  3. <https://cr.openjdk.org/~briangoetz/lambda/lambda-state-final.html>
  4. <https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html>
  5. Lambda Expressions in Java - A Tutorial - <http://angelikalanger.com/Lambdas/Lambdas.pdf>

 

  1. Understanding the closures debate, Klaus Kreft & Angelika Langer, Jun 2008, JavaWorld - <http://www.javaworld.com/javaworld/jw-06-2008/jw-06-closures.html>
  2. Closures for Java, Mark Reinhold, Nov 2009 - <https://blogs.oracle.com/mr/entry/closure>
  3. Java 8: The First Taste of Lambdas, Anton Arhipov, Feb 2013 - <http://zeroturnaround.com/rebellabs/java-8-the-first-taste-of-lambdas/>

更多

  1. The anticipated implementation strategy requires the use of Method Handles and dynamic invocation as specified in JSR 292.
  2. Lambda: A Peek Under the Hood, Guest Author, Sep 2013, JavaOne 2013- <https://blogs.oracle.com/java/post/javaone-2013-lambda-a-peek-under-the-hood>
  3. Translation of Lambda Expressions - <https://cr.openjdk.org/~briangoetz/lambda/lambda-translation.html>
  4. Java 8 的 Lambda 表达式为什么要基于 invokedynamic? - RednaxelaFX
  5. 关于OpenJDK对Java 8 lambda表达式的运行时实现的查看方式 - RednaxelaFX​