Lambda expressions
事实上,如果你回顾历史,并试图找出Java在过去20年中的任何语言改进,你将无法回忆起许多令人兴奋的事情。过去十年中,只有几个并发类(泛型)以及注释,也是 java 中显著的新增内容。Lambda表达式打破了这种干旱,感觉像一个愉快的礼物。
在这篇文章中,我将分三部分介绍 lambda 表达和概念。下面是计划继续。
- Java里的lambda表达式是什么样的?
- Java 8 函数式接口
- lambda表达式的例子
1. Java里的lambda表达式是什么样的?
。在Java语言中,Lambda表达式(或者函数)只是一个匿名函数,一个没有名字没有标识符的函数。他们可以写在任何需要的地方,通常作为一些其他函数的参数。
换句话说,lambda 表达式是作为常量值给出的无名函数,并完全写在需要的地方,通常作为其他函数的参数。
Lambda 表达式最重要的特征是它们在其外观上下文中执行。因此,类似的 lambda 表达式可以在其他一些上下文中以不同的方式执行(即逻辑将相同,但结果将基于传递给函数的不同参数而不同)。
上面的定义充满了关键字,只有当你已经知道什么是lambda表达式时,才能理解。所以,一旦你在下一节中对 lambda 表达式有了更好的理解,我建议你重新阅读上面的段落。
因此,Lambda 显然是一种没有名称和标识符的功能。那有什么大不了的?为什么每个人都这么兴奋?
答案在于函数式编程与面向对象编程 (OOP) 相关的好处。大多数 OOP 语言围绕对象和实例发展,只对待他们的一流公民。另一个重要实体,即功能退居二线。这在 java 中尤其如此,因为在 java 中,函数不能存在于对象之外。函数本身在 java 中没有任何意义,直到它与某些对象或实例相关。
但在函数编程中,可以定义函数,为函数提供引用变量,并将其作为方法参数传递,等等。JavaScript 就是一个很好的例子,您可以在其中传递回调方法,例如,将调用方法传递给 Ajax 调用。这是非常有用的功能,java从一开始就缺乏。现在,使用 java 8,我们也可以使用这些 lambda 表达式。
1.1 Lambda语法
典型应用:
(x, y) -> x + y //这个函数返回两个数的和
请注意x和y的类型,该方法可用用在很多地方。x和y的参数类型也可以是int,Integer,也可以是简单的String。基于上下文,它将添加两个整数或拼接两个字符串
语法:
lambda 表达式的其他语法是:
either
(parameters) -> expression //1
or
(parameters) -> { statements; } //2
or
() -> expression //3
1.2 Lambda例子
让我们来看看lambda表达式的一些例子:
(int a, int b) -> a * b // 输入两个整数并返回乘积
(a, b) -> a - b // 输入两个整数并返回差值
() -> 99 // 不输入任何值返回99
(String a) -> System.out.println(a) // 输入一个string字符,在控制台上打印出来,不返回任何值
a -> 2 * a // 输入一个整数并返回该数字2倍
c -> { //some complex statements } // 输入一个集合并做一些处理
1.3 Lambda表达式特性
lambda表达式的一些特性:
- 一个lambda表达式可以有0个,1个或者多个参数。
- 参数的类型可以显示声明,也可以从上下文中推。
- 多个参数必需用括号括起来,用逗号分隔。空括号用于表示一组空参数。
- 当存在单个参数时,如果推断其类型,则不强制使用括号.就像这样 -> return a*a。
- lambda 表达式的主体可以包含零、一个或多个语句。
- 当匿名函数的返回类型与正文表达式的返回类型相同时,不强制 lambda表达式正文必须具有单个大括号。当正文中有多个语句时,必须用大括号括起来.
因此,我们简要地概述了什么是lambda表达式。请耐心等待,如果你感到迷失,不知道如何在java编程语言中使用。我们将在接下来的30分钟内把一切都弄清楚。让我们开始吧。
在深入探讨 lambda 表达式和 java 编程之间的关系之前,您还必须了解函数式接口。这太重要了
2. Java 8 函数式接口
函数式接口又被称作单独的抽象方法接口(SAM 接口)。顾名思义,他们允许里边正好一个抽象方法。Java8引入了注释,@FunctionalInterface,用来当已注释的接口违法该规定时,返回编译错误。
举个例子,新的Runnable接口定义就像如下这样:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
如果尝试在任何函数接口中添加新方法,编译器将不允许执行此操作,并且将引发编译错误。
目前为止,一切都好。但是,它们与 Lambda 表达式的有什么关系呢?让我们找出答案。
我们知道 Lambda 表达式是匿名函数,没有名称,它们(大部分)作为参数传递给其他函数。嗯,在java方法参数中,参数总是有一个类型,并且寻找这种类型的信息来确定在方法重载甚至简单方法调用的情况下需要调用哪种方法。因此,基本上每个 lambda 表达式也必须转换为某种类型才能做为方法参数被接受。lambda表达式转换的类型永远可以作为函数式接口的类型。
让我们用一个例子来理解它。如果我们必须编写一个线程,它将在控制台中打印"Howtodoinjava",那么最简单的代码将是:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("howtodoinjava");
}
}).start();
如果我们用lambda表达式编写这个任务的代码为:
new Thread(
() -> {
System.out.println("My Runnable");
}
).start();
我们还看到 Runnable 是一个功能接口,具有单个方法run()。因此,当您将 lambda 表达式传递给 Thread 类的构造函数时,编译器会尝试将表达式转换为等效的 Runnable 代码,如第一个代码示例所示。如果编译成功,则一切运行正常,如果编译器无法将表达式转换为等效实现代码,它将抱怨。在此示例中,lambda 表达式将转换为"可运行"类型。
简单地说,lambda 表达式是函数式接口的实例。但是 lambda 表达式本身不包含有关它正在实现的功能接口的信息;该信息是从使用该信息的前后程序中推断的。
3. Java8 lambda表达式例子
我列出了一些代码示例,您可以阅读和分析如何在日常编程中使用 lambda 表达式。
- 迭代List并执行一些操作
List<String> pointList = new ArrayList();
pointList.add("1");
pointList.add("2");
pointList.forEach(p -> {
System.out.println(p);
//Do more work
}
);
- 创建新的Runnable并将其传递给线程
new Thread(
() -> System.out.println("My Runnable");
).start();
- 根据name字段对employees对象排序
public class LambdaIntroduction {
public static void main (String[] ar){
Employee[] employees = {
new Employee("David"),
new Employee("Naveen"),
new Employee("Alex"),
new Employee("Richard")};
System.out.println("Before Sorting Names: "+Arrays.toString(employees));
Arrays.sort(employees, Employee::nameCompare);
System.out.println("After Sorting Names "+Arrays.toString(employees));
}
}
class Employee {
String name;
Employee(String name) {
this.name = name;
}
public static int nameCompare(Employee a1, Employee a2) {
return a1.name.compareTo(a2.name);
}
public String toString() {
return name;
}
}
Output:
Before Sorting Names: [David, Naveen, Alex, Richard]
After Sorting Names [Alex, David, Naveen, Richard]
- 在GUI中添加一个时间监听器
JButton button = new JButton("Submit");
button.addActionListener((e) -> {
System.out.println("Click event triggered !!");
});
网友评论