Java 核心技术卷 I 学习记录八

server/2024/11/19 18:23:04/

Java 核心技术卷 I 学习记录八

  • 六、接口、lambda表达式与内部类
    • 3、lambada表达式
      • 1、为什么引入lambda表达式
      • 2、lambda表达式的语法
      • 3、函数式接口
      • 4、方法引用
      • 5、构造器引用
      • 6、变量作用域
      • 7、处理lambda表达式
      • 8、再谈Comparator

六、接口、lambda表达式与内部类

3、lambada表达式

使用 lambda 表达式采用一种简洁的语法定义代码块。

1、为什么引入lambda表达式

lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。

2、lambda表达式的语法

java">// 检查一个字符串是否比另一个字符串短
first.length() -second.length();// Java是一种强类型语言,指定变量类型
(String first, String second) -> first.length() -second.length();

lambda表达式就是一个代码块,以及必须传入代码的变量规范。
Java中的一种lambda表达式形式:参数,箭头(->)以及一个表达式。如果代码要完成的计算无法放在一个表达式中,就可以像写方法一样,把这些代码放在 {} 中,并包含显式的return语句。

java">// lambda例子:检查一个字符串是否比另一个字符串短
(String first, String second) -> {if (first.length() < second.length()) return -1;else if (first.length() > second.lenght()) return 1;else return 0;
}

即使lambda表达式没有参数,仍然要提供空括号,就像无参数方法一样:

java">() -> { for (int i=100;i>=0;i-- ) System.out.println(i); 
}

如果可以推导出一个lambda表达式的参数类型,就可以忽略类型:

java">Comparator<String> comp= (first, second) // Same as (String first, String second) -> first.length() - second.length();

在这里,编译器可以推导出first和second必然是字符串,因为这个lambda表达式将赋给一个字符串比较器。
如果方法只有一个参数,而且这个参数的类型可以推导出来,甚至还可以省略小括号:

java">ActionListener listener = event ->System.out.println("The time is " + new Date()); // Instead of (event) -> . . . or (ActionEvent event) -> . . .

无需指定lambda表达式的返回类型。lambda表达式的返回类型会根据上下文推导出。

3、函数式接口

对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式。这种接口称为函数式接口(functional interface)。
在Java中,对lambda表达式所能做的也只是能转换为函数式接口。在其他支持函数字面量的程序设计语言中,可以声明函数类型(如(String, String) -> int)、声明这些类型的变量,还可以使用变量保存函数表达式。不过,Java设计者还是决定保持我们熟悉的接口概念,没有为Java语言增加函数类型。

4、方法引用

如果已经有现成的方法已经可以完成你想要传递到其他代码的某个动作。

java">// 假如希望只要出现一个定时器事件就打印这个事件对象
Timer t = new Timer(1000, event -> System.out.println(event));// 如果直接把println方法传递到Timer构造器
Timer t = new Timer(1000, System.out::println);

表达式System.out::println是一个方法引用(method reference),它等价于lambda表达式x -> System.out.println(x);。
要用::操作符分隔方法名与对象或类名。主要有3种情况:

  • object::instanceMethod
  • Class::staticMethod
  • Class::instanceMethod

在前2种情况中,方法引用等价于提供方法参数的lambda表达式。对于第3种情况,第1个参数会成为方法的目标。
可以在方法引用中使用this参数。例如,this::equals等同于x -> this.equals(x)。使用super也是合法的。super::instanceMethod,使用this作为目标,会调用给定方法的超类版本。

5、构造器引用

构造器引用与方法引用很类似,只不过方法名为new。例如,Person::new是Person构造器的一个引用。具体引用哪一个构造器取决于上下文。
可以用数组类型建立构造器引用。例如,int[]::new是一个构造器引用,它有一个参数:即数组的长度。这等价于lambda表达式 x -> new int[x]。
Java有一个限制,无法构造泛型类型T的数组。数组构造器引用对于克服这个限制很有用。表达式new T[n]会产生错误,因为这会改为new Object[n]。对于开发类库的人来说,这是一个问题。

6、变量作用域

可能希望能够在lambda表达式中访问外围方法或类中的变量。
lambda表达式有3个部分:

  • 1、一个代码块;
  • 2、参数;
  • 3、自由变量的值,这是指非参数而且不在代码中定义的变量。

关于代码块以及自由变量值有一个术语:闭包(closure)。如果有人吹嘘他们的语言有闭包,现在你也可以自信地说Java也有闭包。在Java中,lambda表达式就是闭包。

7、处理lambda表达式

使用lambda表达式的重点是延迟执行(deferred execution)毕竟,如果想耍立即执行代码,完全可以直接执行,而无需把它包装在一个lambda表达式中。之所以希望以后再执行代码,这有很多原因,如:

  • 在一个单独的线程中运行代码;
  • 多次运行代码;
  • 在算法的适当位置运行代码(例如,排序中的比较操作);
  • 发生某种情况时执行代码(如,点击了一个按钮,数据到达,等等);
  • 只在必要时才运行代码。

Java API中提供的最重要的函数式接口。

函数式接口参数类型返回类型抽象方法名描述其他方法
Runnablevoidrun作为无参数或返回值的动作运行
SupplierTget提供一个T类型的值
ConsumerTvoidaccept处理一个T类型的值addThen
BiConsumer<T, U>T, Uvoidaccept处理T和U类型的值addThen
Function<T, R>TRapply有一个T类型参数的函数compose, addThen, indetify
BiFunction<T, U, R>T, URapply有T和U类型参数的函数addThen
UnaryOperatorTTapply类型T上的一元操作符compose, addThen, identify
BinaryOperatorT, TTapply类型T上的二元操作符andThen, maxBy, minBy
PredicateTbooleantest布尔值函数and, or, negate, isEqual
BiPredicate<T, U>T, Ubooleantest有两个参数的布尔值函数and, or, negate

基本类型int、long和double的34个可能的规范。最好使用这些特殊化规范来减少自动装箱。

函数式接口参数类型返回类型抽象方法名
BooleanSuppliernonebooleangetAsBoolean
PSuppliernonepgetAsP
PConsumerpvoidaccept
ObjPConsumerT, pvoidaccept
PFunctionpTapply
PToQFunctionpqapplyAsQ
ToPFunctionTpapplyAsP
ToPBiFunction<T, U>T, UpapplyAsP
PUnaryOperatorppapplyAsP
PBinaryOperatorp, ppapplyAsP
PPredicatepbooleantest

8、再谈Comparator

Comparator接口包含很多方便的静态方法来创建比较器。这些方法可以用于lambda表达式或方法引用。
静态comparing方法取一个“键提取器”函数,它将类型T映射为一个可比较的类型(如 String)。对要比较的对象应用这个函数,然后对返回的键完成比较。


http://www.ppmy.cn/server/143264.html

相关文章

【安卓恶意软件检测-论文】DroidEvoler:自我进化的 Android 恶意软件检测系统

DroidEvolver&#xff1a;自我进化的 Android 恶意软件检测系统 摘要 鉴于Android框架的频繁变化和Android恶意软件的不断演变&#xff0c;随着时间的推移以有效且可扩展的方式检测恶意软件具有挑战性。为了应对这一挑战&#xff0c;我们提出了DroidEvolver&#xff0c;这是一…

UML中类图的介绍与使用

类图 UML&#xff08;Unified Modeling Language&#xff0c;统一建模语言&#xff09;中的类图&#xff08;Class Diagram&#xff09;是一种静态结构图&#xff0c;它用于展示系统中的类&#xff08;class&#xff09;、接口&#xff08;interface&#xff09;、协作&#x…

笔记本run个llm, 本地如何启动大模型,大模型ubuntu 3b llm启动,llm部署 ollama 黑盒run大模型

1. 官网&#xff1a; https://ollama.com/ 2. 安装ollama curl -fsSL https://ollama.com/install.sh | sh 3. run个3b模型: https://ollama.com/search 4. 命令&#xff1a; ollama run llama3.2 5&#xff1a; run之后样子&#xff0c;使用的是cpu跑的。如果有gpu&…

港大ArcLab最新开源DEIO:第一个学习与传统非线性图优化紧密结合的单目事件惯性里程计

原文链接&#xff1a;港大ArcLab最新开源DEIO&#xff1a;第一个学习与传统非线性图优化紧密结合的单目事件惯性里程计 导读 本文介绍了一种名为 DEIO&#xff08;Deep Event Inertial Odometry&#xff09;的新型单目深度事件惯性里程计框架。该方法创新性地将深度学习与传统…

第二十四章 TCP 客户端 服务器通信 - 当前 TCP 设备

文章目录 第二十四章 TCP 客户端 服务器通信 - 当前 TCP 设备当前 TCP 设备TCP 设备的 USE 命令 第二十四章 TCP 客户端 服务器通信 - 当前 TCP 设备 当前 TCP 设备 可以使用 %SYSTEM.TCPDevice方法返回当前 TCP 设备的 IP 地址和端口号。可以使用 Help() 方法列出这些方法&a…

游戏引擎学习第16天

视频参考:https://www.bilibili.com/video/BV1mEUCY8EiC/ 这些字幕讨论了编译器警告的概念以及如何在编译过程中启用和处理警告。以下是字幕的内容摘要&#xff1a; 警告的定义&#xff1a;警告是编译器用来告诉你某些地方可能存在问题&#xff0c;尽管编译器不强制要求你修复…

论文的科技查新报告是什么?有什么用途?

一、论文的科技查新报告是什么 论文的科技查新与一般科技查新有一些不同之处。 在论文的科技查新中&#xff0c;主要是针对特定的研究课题进行查新&#xff0c;以获取与该课题相关的最新研究成果和文献。 与一般科技查新相比&#xff0c;论文的科技查新更加注重对学术界的研究…

Ribbon 与 Feign:微服务调用中的差异探究

一、引言 在微服务架构蓬勃发展的当下&#xff0c;服务之间的高效协作与调用成为了构建分布式系统的关键环节。Spring Cloud 为我们提供了诸多实用的组件来助力微服务间的交互&#xff0c;其中 Ribbon 和 Feign 备受关注且应用广泛。然而&#xff0c;不少开发者对于它们之间的…