Java8(1)之Lambda表达式初步与函数式接口
Lambda表达式初步
介绍
什么是Lambda表达式?
在如 Lisp、Python、Ruby 编程语言中,Lambda 是一个用于表示匿名函数或闭包的运算符
为何需要lambda表达式?
- 在 Java 中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法。
- 在 JavaScript 中,函数参数是一个函数,返回值是另一个函数的情况是非常常见的;JavaScript 是一门非常典型的函数式语言。
看如下匿名内部类实例:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; public class SwingTest {
public static void main(String[] args) {
JFrame jFrame = new JFrame("My JFrame");
JButton jButton = new JButton("My Button");
// 匿名内部类
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button Pressed");
}
});
jFrame.add(jButton);
jFrame.pack();
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
例 1:
如上代码很简单,通过第 10 行给第 8 行的按钮注册了一个监听器。而我们知道,当事件触发真正起作用的实际上是执行第 12 行的 actionPerformed 方法,为此我们创建了 ActionListener 实例。
而 Lambda 表达式可以让我们只专注于方法的实现,在注册监听器时我们可以忽略具体需要创建哪个类型的实例。其实在 Idea 中本身就已经给我们提示了,如下:
即匿名内部类的写法是可以用 Lambda 表达式替换的,如下:
import javax.swing.*; public class SwingTest {
public static void main(String[] args) {
JFrame jFrame = new JFrame("My JFrame");
JButton jButton = new JButton("My Button");
// Lambda 表达式
jButton.addActionListener(event -> System.out.println("jButton Pressed"));
jFrame.add(jButton);
jFrame.pack();
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
例 2:
在例 2 中通过第 8 行的 Lambda 表达式替换了例 1 中 10-15 行的匿名内部类写法,不仅代码更简洁,而且含义更直观明了。
基本结构
在 Java 8 中 Lambda 表达式最原始的写法如下:
(类型 prarm1,类型 param2,类型 param3, ...) -> {
// 方法体
}
可以将参数类型省略,编译器可自动推断:
(prarm1, param2, param3, ...) -> {
// 方法体
}
如果只有一个参数,还可以省略小括号:
prarm1 -> {
// 方法体
}
如果方法体只有一行代码,那么大括号也可以省略:
prarm1 -> <方法实现>
用例 2 中的 Lambda 为例演变过程如下:
// 原始写法
jButton.addActionListener((ActionEvent event) -> {
System.out.println("jButton Pressed");
});
// 省略参数类型
jButton.addActionListener((event) -> {
System.out.println("jButton Pressed");
});
// 省略小括号
jButton.addActionListener(event -> {
System.out.println("jButton Pressed");
});
// 省略大括号
jButton.addActionListener(event -> System.out.println("jButton Pressed"));
函数式接口
介绍
在 Java 8 中, Iterable 接口中新增了一个默认函数 forEach 让我们可以更方便的遍历它:
package java.lang; import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer; public interface Iterable<T> {
Iterator<T> iterator(); default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
} default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
java.lang.Iterable
可以看到它接收一个 java.util.function.Consumer 类型参数,查看 JavaDoc:
该类上标注了一个 @FunctionalInterface 注解,并且注释中还说明了这个接口是一个函数式接口。查看该注解的 JavaDoc:
可以获得如下信息:
- 这是一个信息性注解,用于标注在一个接口上使一个接口成为函数式接口。
- 从概念上来说,一个函数式接口有且只能有一个抽象方法。
- 如果在接口中仅定义了一个抽象方法并且它覆盖了 java.lang.Object 类中公开的方法,那么这个接口就不是函数式接口。
- 函数式接口的实例可以通过 Lambda 表达式、方法引用或构造方法引用来创建。
- 如果被该注解标注的类型不满足下面两个条件,那么编译器将生成错误信息。
- 该类型是一个接口,不可以是注解类型、枚举、类。
- 被注解类型必须满足函数式注解的要求。
- 如果一个接口满足了函数式接口的要求,但它没有标注该注解,编译器也会将它看作是函数式接口。
Lambda表达式的作用
看如下示例:
package zze.java8; @FunctionalInterface
interface MyInterface {
void test();
} public class Test2 {
public void test(MyInterface myInterface) {
System.out.println("Test2.test");
myInterface.test();
} public static void main(String[] args) {
Test2 test2 = new Test2();
test2.test(() ->System.out.println("MyInterface.test"));
/*
* Test2.test
* MyInterface.test
*/
}
}
可以看到, Test2 的实例方法 test 实际上是接收一个 MyInterface 对象,而 MyInterface 是一个函数式接口,所以我们可以通过传入 Lambda 表达式作为 myInterface 参数,即:此时传入的 Lambda 表达式就是对函数函数式接口 MyInterface 的实现对象。所以上面代码其实也可以修改为如下:
Test2 test2 = new Test2();
MyInterface myInterface = () -> System.out.println("MyInterface.test");
test2.test(myInterface);
System.out.println(myInterface.getClass());
System.out.println(myInterface.getClass().getSuperclass());
System.out.println(myInterface.getClass().getInterfaces()[]);
/*
Test2.test
MyInterface.test
class zze.java8.Test2$$Lambda$1/990368553
class java.lang.Object
interface zze.java8.MyInterface
*/
总结:
- Lambda 表达式为 Java 添加了缺失的函数式编程特性,使我们能将函数当做一等公民看待。
- 在将函数作为一等公民的语言中(如 Python、JavaScript),Lambda 表达式的类型是函数。但在 Java 中,Lambda 表达式是一个对象,它们必须依附于一类特别的对象类型——函数式接口(functional interface)。
Java8(1)之Lambda表达式初步与函数式接口的更多相关文章
- java8学习之Lambda表达式初步与函数式接口
对于Java8其实相比之前的的版本增加的内容是相当多的,其中有相当一大块的内容是关于Lambda表达式与Stream API,而这两部分是紧密结合而不能将其拆开来对待的,但是是可以单独使用的,所以从学 ...
- java8学习之Lambda表达式继续探讨&Function接口详解
对于上次[http://www.cnblogs.com/webor2006/p/8186039.html]已经初步引入的Java8中Stream流的概念,其中使用了map的操作,它需要接受一个Func ...
- Java8新特性-Lambda表达式是什么?
目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...
- 怒学Java8系列一:Lambda表达式
PDF文档已上传Github Github:https://github.com/zwjlpeng/Angrily_Learn_Java_8 第一章 Lambda 1.1 引言 课本上说编程有两种模 ...
- 乐字节-Java8新特性-Lambda表达式
上一篇文章我们了解了Java8新特性-接口默认方法,接下来我们聊一聊Java8新特性之Lambda表达式. Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作 ...
- java8新特性——Lambda表达式
上文中简单介绍了一下java8得一些新特性,与优点,也是为本次学习java8新特性制定一个学习的方向,后面几篇会根据上文中得新特性一一展开学习.本文就从java8新特性中比较重要的Lambda表达式开 ...
- JAVA8学习——深入浅出Lambda表达式(学习过程)
JAVA8学习--深入浅出Lambda表达式(学习过程) lambda表达式: 我们为什么要用lambda表达式 在JAVA中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法. 在 ...
- Java8 新特性lambda表达式(一)初始
本篇参考Richard Warburton的 java8 Lambdas :Functional Programming for the Masses 学习lambda表达式之前,需要知道什么是函数式 ...
- Java8学习笔记----Lambda表达式 (转)
Java8学习笔记----Lambda表达式 天锦 2014-03-24 16:43:30 发表于:ATA之家 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人 ...
随机推荐
- javascript事件委托的原理与实现
事件委托 事件流 捕获:查找目标元素: 目标:执行目标的事件: 冒泡:依次执行祖先元素的事件. onmouseenter和onmouseleave不支持冒泡: onmouseover和onmouseo ...
- javascript中字符串的方法
字符串的方法 charAt();返回字符串指定索引的字符: concat();连接两个或多个字符串: indexOf();返回字符串中检索指定字符第一次出现的位置: lastIndexOf();返回字 ...
- 【java】字符串处理技巧记录
字符串处理跟抖机灵似得... 1.统计字符串中含有子字符串的个数 例如"abcdefgabehab"中含有子字符串"ab"的个数为3. (str.length( ...
- Ubuntu18.04安装Python虚拟环境
仅为使用Ubuntu18.04的Python开发人员作参考 1.安装Ubuntu18.04虚拟环境 sudo apt install virtualenv sudo apt install virtu ...
- ios 修改导航栏返回按钮的图片
修改导航栏返回按钮的图片 方法1: [UINavigationBar appearance].backIndicatorTransitionMaskImage = [UIImage imageName ...
- pandas导入导出数据-【老鱼学pandas】
pandas可以读写如下格式的数据类型: 具体详见:http://pandas.pydata.org/pandas-docs/version/0.20/io.html 读取csv文件 我们准备了一个c ...
- SQL反模式学习笔记22 伪键洁癖,整理数据
目标:整理数据,使不连续的主键Id数据记录变的连续. 反模式:填充断档的数据空缺. 1.不按照顺序分配编号 在插入新行时,通过遍历表,找到的第一个未分配的主键编号分配给新行,来代替原来自动分配的伪主键 ...
- ACA:利用ACA解决TSP优化最佳路径问题——Jason niu
load citys_data.mat n = size(citys,1); D = zeros(n,n); for i = 1:n for j = 1:n if i ~= j D(i,j) = sq ...
- WebLogic使用总结(一)——WebLogic安装
一.下载WebLogic 到Oracle官网http://www.oracle.com/ 下载WebLogic(根据自己的情况选择),本文档下载的是Generic WebLogic Server an ...
- Beta(2/7)
鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...