Android lambda表达式笔记(二)

本文介绍Java SE 8引入的Lambda表达式及其背后的函数式编程思想,探讨了Lambda表达式的语法改进、方法引用、目标类型推导等特性。此外,文章还详细解释了函数式接口的概念以及Java如何通过这种方式支持轻量级的行为封装。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于
本文介绍了Java SE 8中新引入的lambda语言特性以及这些特性背后的设计思想。这些特性包括:

lambda表达式(又被成为“闭包”或“匿名方法”)
方法引用和构造方法引用
扩展的目标类型和类型推导
接口中的默认方法和静态方法
1. 背景
Java是一门面向对象编程语言。面向对象编程语言和函数式编程语言中的基本元素(Basic Values)都可以动态封装程序行为:面向对象编程语言使用带有方法的对象封装行为,函数式编程语言使用函数封装行为。但这个相同点并不明显,因为Java的对象往往比较“重量级”:实例化一个类型往往会涉及不同的类,并需要初始化类里的字段和方法。

不过有些Java对象只是对单个函数的封装。例如下面这个典型用例:Java API中定义了一个接口(一般被称为回调接口),用户通过提供这个接口的实例来传入指定行为,例如:

public interface ActionListener {
void actionPerformed(ActionEvent e);
}
这里并不需要专门定义一个类来实现ActionListener接口,因为它只会在调用处被使用一次。用户一般会使用匿名类型把行为内联(inline):

button.addActionListener(new ActionListener) {
public void actionPerformed(ActionEvent e) {
ui.dazzle(e.getModifiers());
}
}
很多库都依赖于上面的模式。对于并行API更是如此,因为我们需要把待执行的代码提供给并行API,并行编程是一个非常值得研究的领域,因为在这里摩尔定律得到了重生:尽管我们没有更快的CPU核心(core),但是我们有更多的CPU核心。而串行API就只能使用有限的计算能力。

随着回调模式和函数式编程风格的日益流行,我们需要在Java中提供一种尽可能轻量级的将代码封装为数据(Model code as data)的方法。匿名内部类并不是一个好的选择,因为:

语法过于冗余
匿名类中的this和变量名容易使人产生误解
类型载入和实例创建语义不够灵活
无法捕获非final的局部变量
无法对控制流进行抽象
上面的多数问题均在Java SE 8中得以解决:

通过提供更简洁的语法和局部作用域规则,Java SE 8彻底解决了问题1和问题2
通过提供更加灵活而且便于优化的表达式语义,Java SE 8绕开了问题3
通过允许编译器推断变量的“常量性”(finality),Java SE 8减轻了问题4带来的困扰
不过,Java SE 8的目标并非解决所有上述问题。因此捕获可变变量(问题4)和非局部控制流(问题5)并不在Java SE 8的范畴之内。(尽管我们可能会在未来提供对这些特性的支持)

  1. 函数式接口(Functional interfaces)
    尽管匿名内部类有着种种限制和问题,但是它有一个良好的特性,它和Java类型系统结合的十分紧密:每一个函数对象都对应一个接口类型。之所以说这个特性是良好的,是因为:

接口是Java类型系统的一部分
接口天然就拥有其运行时表示(Runtime representation)
接口可以通过Javadoc注释来表达一些非正式的协定(contract),例如,通过注释说明该操作应可交换(commutative)
上面提到的ActionListener接口只有一个方法,大多数回调接口都拥有这个特征:比如Runnable接口和Comparator接口。我们把这些只拥有一个方法的接口称为函数式接口。(之前它们被称为SAM类型,即单抽象方法类型(Single Abstract Method))

我们并不需要额外的工作来声明一个接口是函数式接口:编译器会根据接口的结构自行判断(判断过程并非简单的对接口方法计数:一个接口可能冗余的定义了一个Object已经提供的方法,比如toString(),或者定义了静态方法或默认方法,这些都不属于函数式接口方法的范畴)。不过API作者们可以通过@FunctionalInterface注解来显式指定一个接口是函数式接口(以避免无意声明了一个符合函数式标准的接口),加上这个注解之后,编译器就会验证该接口是否满足函数式接口的要求。

实现函数式类型的另一种方式是引入一个全新的结构化函数类型,我们也称其为“箭头”类型。例如,一个接收String和Object并返回int的函数类型可以被表示为(String, Object) -> int。我们仔细考虑了这个方式,但出于下面的原因,最终将其否定:

它会为Java类型系统引入额外的复杂度,并带来结构类型(Structural Type)和指名类型(Nominal Type)的混用。(Java几乎全部使用指名类型)
它会导致类库风格的分歧——一些类库会继续使用回调接口,而另一些类库会使用结构化函数类型
它的语法会变得十分笨拙,尤其在包含受检异常(checked exception)之后
每个函数类型很难拥有其运行时表示,这意味着开发者会受到类型擦除(erasure)的困扰和局限。比如说,我们无法对方法m(T->U)和m(X->Y)进行重载(Overload)
所以我们选择了“使用已知类型”这条路——因为现有的类库大量使用了函数式接口,通过沿用这种模式,我们使得现有类库能够直接使用lambda表达式。例如下面是Java SE 7中已经存在的函数式接口:

java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.beans.PropertyChangeListener
除此之外,Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口,例如:

Predicate——接收T对象并返回boolean
Consumer——接收T对象,不返回值
Function

内容概要:本文介绍了基于Python实现的SSA-GRU(麻雀搜索算法优化门控循环单元)时间序列预测项目。项目旨在通过结合SSA的全局搜索能力和GRU的时序信息处理能力,提升时间序列预测的精度和效率。文中详细描述了项目的背景、目标、挑战及解决方案,涵盖了从数据预处理到模型训练、优化及评估的全流程。SSA用于优化GRU的超参数,如隐藏层单元数、学习率等,以解决传统方法难以捕捉复杂非线性关系的问题。项目还提供了具体的代码示例,包括GRU模型的定义、训练和验证过程,以及SSA的种群初始化、迭代更新策略和适应度评估函数。; 适合人群:具备一定编程基础,特别是对时间序列预测和深度学习有一定了解的研究人员和技术开发者。; 使用场景及目标:①提高时间序列预测的精度和效率,适用于金融市场分析、气象预报、工业设备故障诊断等领域;②解决传统方法难以捕捉复杂非线性关系的问题;③通过自动化参数优化,减少人工干预,提升模型开发效率;④增强模型在不同数据集和未知环境中的泛化能力。; 阅读建议:由于项目涉及深度学习和智能优化算法的结合,建议读者在阅读过程中结合代码示例进行实践,理解SSA和GRU的工作原理及其在时间序列预测中的具体应用。同时,关注数据预处理、模型训练和优化的每个步骤,以确保对整个流程有全面的理解。
内容概要:本文详细介绍了如何使用PyQt5创建一个功能全面的桌面备忘录应用程序,涵盖从环境准备、数据库设计、界面设计到主程序结构及高级功能实现的全过程。首先,介绍了所需安装的Python库,包括PyQt5、sqlite3等。接着,详细描述了SQLite数据库的设计,创建任务表和类别表,并插入默认类别。然后,使用Qt Designer设计UI界面,包括主窗口、任务列表、工具栏、过滤器和日历控件等。主程序结构部分,展示了如何初始化UI、加载数据库数据、显示任务列表以及连接信号与槽。任务管理功能方面,实现了添加、编辑、删除、标记完成等操作。高级功能包括类别管理、数据导入导出、优先级视觉标识、到期日提醒、状态管理和智能筛选等。最后,提供了应用启动与主函数的代码,并展望了扩展方向,如多用户支持、云同步、提醒通知等。 适合人群:零基础或初学者,对Python和桌面应用程序开发感兴趣的开发者。 使用场景及目标:①学习PyQt5的基本使用方法,包括界面设计、信号与槽机制;②掌握SQLite数据库的基本操作,如创建表、插入数据、查询等;③实现一个完整的桌面应用程序,具备增删改查和数据持久化功能;④了解如何为应用程序添加高级特性,如类别管理、数据导入导出、到期日提醒等。 阅读建议:此资源不仅适用于零基础的学习者,也适合有一定编程经验的开发者深入理解PyQt5的应用开发。建议读者跟随教程逐步实践,结合实际操作来理解和掌握每个步骤,同时可以尝试实现扩展功能,进一步提升自己的开发技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值