Java 之 Functional Interfaces, Lambda Expressions

简述

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} [ ]}

Why?

The free lunch is over^. 多核时代已经到来,现代语言要能充分利用多核算力,并发安全,简洁灵活,稳定高效。

虽有 anonymous inner classes,语法不够简洁,执行不够灵活,值得加入一个讨论已久的特性,lambda expression,再辅以更多优化,就有望走出争论,迈向新时代。

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

Default methods provide a more object-oriented way to add concrete behavior to an interface. Default methods have an implementation that is inherited by classes that do not override it.

In addition to allowing code in interfaces in the form of default methods, Java SE 8 also introduces the ability to place static methods in interfaces as well. This allows helper methods that are specific to an interface to live with the interface, rather than in a side class.

A Peek Under the Hood

  • typing, representation
  • Translation strategies, Desugaring lambdas to methods, Factories and metafactories
  • Serialization

参考

  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​
  6. Java中普通lambda表达式和方法引用本质上有什么区别? - RednaxelaFX​

 

  1. James Gosling, <http://blogs.sun.com/jag/entry/closures> 🔗
  2. <https://www.infoworld.com/article/2073110/java-7--the-return-of-closures.html>
posted @ 2023-03-22 20:00  UPeRVv  阅读(22)  评论(0编辑  收藏  举报