但是,新的函数式结构在流 API 之外具有其它用途 。考虑一个 Java GUI 程序,该程序带有一个供用户按下的按钮,例如,按下以获取当前时间 。按钮按下的事件处理程序可能编写如下:
JButton updateCurrentTime = new JButton("Update current time");updateCurrentTime.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { currentTime.setText(new Date().toString()); }});
这个简短的代码段很难解释 。关注第二行,其中方法 addActionListener 的参数开始如下:
new ActionListener() {
这似乎是错误的,因为 ActionListener 是一个抽象接口,而抽象类型不能通过调用 new 实例化 。但是,事实证明,还有其它一些实例被实例化了:一个实现此接口的未命名内部类 。如果上面的代码封装在名为 OldJava 的类中,则该未命名的内部类将被编译为 OldJava$1.class 。actionPerformed 方法在这个未命名的内部类中被重写 。
现在考虑使用新的函数式结构进行这个令人耳目一新的更改:
updateCurrentTime.addActionListener(e -> currentTime.setText(new Date().toString()));
lambda 表达式中的参数 e 是一个 ActionEvent 实例,而 lambda 的主体是对按钮上的 setText 的简单调用 。
函数式接口和函数组合到目前为止,使用的 lambda 已经写好了 。但是,为了方便起见,我们可以像引用封装方法一样引用 lambda 表达式 。以下一系列简短示例说明了这一点 。
考虑以下接口定义:
@FunctionalInterface // 可选,通常省略interface BinaryIntOp { abstract int compute(int arg1, int arg2); // abstract 声明可以被删除}
注释 @FunctionalInterface 适用于声明唯一抽象方法的任何接口;在本例中,这个抽象接口是 compute 。一些标准接口,(例如具有唯一声明方法 run 的 Runnable 接口)同样符合这个要求 。在此示例中,compute 是已声明的方法 。该接口可用作引用声明中的目标类型:
BinaryIntOp div = (arg1, arg2) -> arg1 / arg2;div.compute(12, 3); // 4
包 java.util.function 提供各种函数式接口 。以下是一些示例 。
下面的代码段介绍了参数化的 Predicate 函数式接口 。在此示例中,带有参数 String 的 Predicate<String> 类型可以引用具有 String 参数的 lambda 表达式或诸如 isEmpty 之类的 String 方法 。通常情况下,Predicate 是一个返回布尔值的函数 。
Predicate<String> pred = String::isEmpty; // String 方法的 predicate 声明String[] strings = {"one", "two", "", "three", "four"};Arrays.asList(strings) .stream() .filter(pred) // 过滤掉非空字符串 .forEach(System.out::println); // 只打印空字符串
在字符串长度为零的情况下,isEmpty Predicate 判定结果为 true 。因此,只有空字符串才能进入管道的 forEach 阶段 。
下一段代码将演示如何将简单的 lambda 或方法引用组合成更丰富的 lambda 或方法引用 。考虑这一系列对 IntUnaryOperator 类型的引用的赋值,它接受一个整型参数并返回一个整型值:
IntUnaryOperator doubled = n -> n * 2;IntUnaryOperator tripled = n -> n * 3;IntUnaryOperator squared = n -> n * n;
IntUnaryOperator 是一个 FunctionalInterface,其唯一声明的方法为 applyAsInt 。现在可以单独使用或以各种组合形式使用这三个引用 doubled、tripled 和 squared:
int arg = 5;doubled.applyAsInt(arg); // 10tripled.applyAsInt(arg); // 15squared.applyAsInt(arg); // 25
推荐阅读
- c语言退出程序命令exit c语言exit函数用法
- 矩阵所有元素求和的公式 matlab矩阵求和函数
- c语言圆的面积编程 c语言阶乘函数怎么写
- 同位语从句经典例句 求同位语的具体用法和例句分析。
- spend的用法
- 并列连词 并列连词与从属连词的用法区别?
- 《如龙:极》鬼炎用法技巧解析攻略
- 对马岛之魂辅助功能有什么 对马之魂辅助功能用法介绍
- 团战经理骑士怎么用 团战经理骑士用法详解
- 团战经理狙击手好用吗 团战经理狙击手用法介绍