0

0

java中lambda表达式语法说明

高洛峰

高洛峰

发布时间:2017-01-23 15:42:10

|

2046人浏览过

|

来源于php中文网

原创

语法说明

一个lambda表达式由如下几个部分组成:

1. 在圆括号中以逗号分隔的形参列表。在CheckPerson.test方法中包含一个参数p,代表了一个Person类的实例。注意:lambda表达式中的参数的类型是可以省略的;此外,如果只有一个参数的话连括号也是可以省略的。比如上一节曾提到的代码:

p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
    && p.getAge() <= 25

2. 箭头符号:->。用来分隔参数和函数体。

3. 函数体。由一个表达式或代码块组成。在上一节的例子中使用了这样的表达式:

立即学习Java免费学习笔记(深入)”;

   
p.getGender() == Person.Sex.MALE
      && p.getAge() >= 18
      && p.getAge() <= 25

如果使用的是表达式,java运行时会计算并返回表达式的值。另外,还可以选择在代码块中使用return语句:

p -> {
  return p.getGender() == Person.Sex.MALE
      && p.getAge() >= 18
      && p.getAge() <= 25;
}

不过return语句并不是表达式。在lambda表达式中需要将语句用花括号括起来,然而却没有必要在只是调用一个返回值为空的方法时也用花括号括起来,所以如下的写法也是正确的:

email -> System.out.println(email)

lambda表达式和方法的声明看起来有很多类似的地方。所以也可以把lambda表达式视为匿名方法,也就是没有定义名字的方法。

以上提到的lambda表达式都是只使用了一个参数作为形参的表达式。下面的实例类,Caulator,演示了如何使用多个参数作为形参:

package com.zhyea.zytools;
 
public class Calculator {
 
  interface IntegerMath {
    int operation(int a, int b);
  }
 
  public int operateBinary(int a, int b, IntegerMath op) {
    return op.operation(a, b);
  }
 
  public static void main(String... args) {
    Calculator myApp = new Calculator();
    IntegerMath addition = (a, b) -> a + b;
    IntegerMath subtraction = (a, b) -> a - b;
    System.out.println("40 + 2 = " + myApp.operateBinary(40, 2, addition));
    System.out.println("20 - 10 = " + myApp.operateBinary(20, 10, subtraction));
  }
}

代码中operateBinary方法使用了两个整型参数执行算数操作。这里的算数操作本身就是IntegerMath接口的一个实例。在上面的程序中使用lambda表达式定义了两个算数操作:addition和subtraction。执行程序会打印如下内容:

40 + 2 = 42
20 - 10 = 10

访问外部类的局部变量 

类似于局部类或匿名类,lambda表达式也可以访问外部类的局部变量。不同的是,使用lambda表达式时无需考虑覆盖之类的问题。lambda表达式只是一个词法上的概念,这意味着它不需要从超类中继承任何名称,也不会引入新的作用域。也就是说,在lambda表达式中的声明和在它的外部环境中的声明意义是一样的。在下面的例子中对此作了演示:

package com.zhyea.zytools;
 
import java.util.function.Consumer;
 
public class LambdaScopeTest {
 
  public int x = 0;
 
  class FirstLevel {
 
    public int x = 1;
 
    void methodInFirstLevel(int x) {
      //如下的语句会导致编译器在statement A处报错“local variables referenced from a lambda expression must be final or effectively final”
      // x = 99;
      Consumer myConsumer = (y) ->{
        System.out.println("x = " + x); // Statement A
        System.out.println("y = " + y);
        System.out.println("this.x = " + this.x);
        System.out.println("LambdaScopeTest.this.x = " + LambdaScopeTest.this.x);
      };
 
      myConsumer.accept(x);
    }
  }
 
  public static void main(String... args) {
    LambdaScopeTest st = new LambdaScopeTest();
    LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
    fl.methodInFirstLevel(23);
  }
}

   

这段代码会输出如下内容:

   
x = 23
y = 23
this.x = 1
LambdaScopeTest.this.x = 0

如果使用示例中lambda表达式myConsumer中的参数y替换为x,编译器就会报错:

Consumer myConsumer = (x) ->{
      // ....
    };

编译器报错信息是:“variable x is already defined in method methodInFirstLevel(int)”,就是说在方法methodInFirstLevel中已经定义了变量x。报错是因为lambda表达式不会引入新的作用域。也因此呢,可以在lambda表达式中直接访问外部类的域字段、方法以及形参。在这个例子中,lambda表达式myConsumer直接访问了方法methodInFirstLevel的形参x。而访问外部类的成员时也是直接使用this关键字。在这个例子中this.x指的就是FirstLevel.x。

然而,和局部类或匿名类一样,lambda表达式也只能访问局部变量或外部被声明为final(或等同于final)的成员。比如,我们将示例代码methodInFirstLevel方法中“x=99”前面的注释去掉:

//如下的语句会导致编译器在statement A处报错“local variables referenced from a lambda expression must be final or effectively final”
x = 99;
Consumer myConsumer = (y) ->{
  System.out.println("x = " + x); // Statement A
  System.out.println("y = " + y);
  System.out.println("this.x = " + this.x);
  System.out.println("LambdaScopeTest.this.x = " + LambdaScopeTest.this.x);
};

因为在这段语句中修改了参数x的值,使得methodInFirstLevel的参数x不可以再被视为final式的。因此java编译器就会在lambda表达式访问局部变量x的地方报出类似“local variables referenced from a lambda expression must be final or effectively final”这样的错误。

目标类型

该如何判断lambda表达式的类型呢。再来看一下筛选适龄服兵役人员的代码:

   
p -> p.getGender() == Person.Sex.MALE
       && p.getAge() >= 18
       && p.getAge() <= 25

这段代码在两处用到过:

public static void printPersons(List roster, CheckPerson tester) —— 方案三 
public void printPersonsWithPredicate(List roster, Predicate tester) —— 方案六 

百度GBI
百度GBI

百度GBI-你的大模型商业分析助手

下载

在调用printPersons方法时,这个方法期望一个CheckPerson 类型的参数,此时上面的那个表达式就是一个CheckPerson 类型的表达式。在调用printPersonsWithPredicate方法时,期望一个Predicate类型的参数,此时同样的表达式就是Predicate类型的。像这样子的,由方法期望的类型来决定的类型就叫做目标类型(其实我觉得scala中的类型推断用在这里更合适)。java编译器就是通过目标类型的上下文语境或者发现lambda表达式时的位置来判断lambda表达式的类型的。这也就意味着只能在Java编译器可以推断出类型的位置使用Lambda表达式:

变量声明;

赋值;

返回语句;

数组初始化;

方法或者构造器参数;

lambda表达式方法体;

条件表达式(?:);

抛出异常时。 

目标类型和方法参数

对于方法参数,Java编译器还需要依赖两个语言特性来决定目标类型:重载解析和类型参数推断。

看一下下面的这两个函数式接口( java.lang.Runnable and java.util.concurrent.Callable):

public interface Runnable {
    void run();
  }
 
  public interface Callable {
    V call();
  }

Runnable.run()方法没有返回值,而Callable.call()方法有。

假设我们像下面这样重载了invoke方法:

void invoke(Runnable r) {
   r.run();
 }
 
  T invoke(Callable c) {
   return c.call();
 }

那么在下面的语句中将会调用哪个方法呢:

String s = invoke(() -> "done");

调用的是invoke(Callable),因为这个方法有返回值,而invoke(Runnable)没有返回值。在这种情况下lambda表达式(() -> “done”)的类型是Callable

序列化

如果一个lambda表达式的目标类型还有它调用的参数的类型都是可序列化的,那么lambda表达式也是可序列化的。然而就像内部类一样,强烈不建议对lambda表达式进行序列化。

更多java中lambda表达式语法说明相关文章请关注PHP中文网!

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

2

2026.01.31

go语言 math包
go语言 math包

本专题整合了go语言math包相关内容,阅读专题下面的文章了解更多详细内容。

1

2026.01.31

go语言输入函数
go语言输入函数

本专题整合了go语言输入相关教程内容,阅读专题下面的文章了解更多详细内容。

1

2026.01.31

golang 循环遍历
golang 循环遍历

本专题整合了golang循环遍历相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.31

Golang人工智能合集
Golang人工智能合集

本专题整合了Golang人工智能相关内容,阅读专题下面的文章了解更多详细内容。

1

2026.01.31

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

76

2026.01.31

高干文在线阅读网站大全
高干文在线阅读网站大全

汇集热门1v1高干文免费阅读资源,涵盖都市言情、京味大院、军旅高干等经典题材,情节紧凑、人物鲜明。阅读专题下面的文章了解更多详细内容。

73

2026.01.31

无需付费的漫画app大全
无需付费的漫画app大全

想找真正免费又无套路的漫画App?本合集精选多款永久免费、资源丰富、无广告干扰的优质漫画应用,涵盖国漫、日漫、韩漫及经典老番,满足各类阅读需求。阅读专题下面的文章了解更多详细内容。

67

2026.01.31

漫画免费在线观看地址大全
漫画免费在线观看地址大全

想找免费又资源丰富的漫画网站?本合集精选2025-2026年热门平台,涵盖国漫、日漫、韩漫等多类型作品,支持高清流畅阅读与离线缓存。阅读专题下面的文章了解更多详细内容。

19

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
AngularJS教程
AngularJS教程

共24课时 | 3.2万人学习

【李炎恢】ThinkPHP8.x 后端框架课程
【李炎恢】ThinkPHP8.x 后端框架课程

共50课时 | 4.5万人学习

php初学者入门课程
php初学者入门课程

共10课时 | 0.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号