
Lambda表达式,也常常叫做闭包,是一个在很多现代程序语言中十分流行的特性。在众多不同的原因中当中,Java平台最迫切的原因之一是lambda表达式能简化多线程上的集合的分布式处理。列表和集是有代表性,在客户端代码获取一个来自集合的迭代器,那么使用通过元素的迭代和轮流取出并处理他们。如果在并行中处理不同元素,客户端代码的有责任把它组织起来。
在Java 8中,目的是替代集合提供的函数,获取函数并使用他们以各种不同的方法处理元素(我们将使用非常简单的函数forEach为例子,通过它获取一个函数并适用于任何元素)优势是转变集合在内部迭代并组织那些元素,将来自客户端的并行代码转移到库代码中。
可是 ,为了让客户端代码在这里取得优势,需要一个简单方法给集合函数提供一个函数。当前标准的方式是建立一个匿名类实现对应的接口。但定义内部匿名类的语法太笨拙了
举个例子,在forEach函数集合上将获取Block接口的一个实例并调用它的apply函数为任何元素。
interface Block { void apply(T t); }
假设我们想使用forEach在List中的Point元素(JavaawtPoint)上调换x和y的坐标。使用内部匿名类实现Block我们通过调换函数,像这样:
pointListforEach(new Block() {
public void apply(Point p) {
pmove(py, px);
}
});
可是,使用Lambda,同样的效果可以用更简介的形式来写:
pointListforEach(p -> pmove(py, px));
这是lambda表达式,也就是匿名函数,对于
personsforEach(p->psetLastName("Doe"));
这句代码,persons是一个list,forEach是一个内部迭代的方法,p->psetLastName("Doe")是一个匿名函数对象。
这个语句等价于
for (Person p : persons) {
psetLastName("Doe");
}
但是用for循环是外部迭代,速度略慢。
p->psetLastName("Doe")
p是指list当中取出的对象,p可以自己定义,你写a也可以,相应的就要变成
a->asetLastName("Doe")
->是lambda表达式的符号,->左边的对象去传入lambda函数体psetLastName("Doe"),是前面传入的p去调用setLastName方法,如果要调用多个方法,那么方法体要用花括号包含
例如personsforEach(p->{
psetLastName("Doe")
Systemoutprintln(p);
});
综上所述
personsforEach(p->psetLastName("Doe"));
是把p->psetLastName("Doe");这个函数对象,给了persons的迭代器,让迭代器用这个函数去对集合中的每一个对象使用
有了lambda,你可以这样定义一个新的线程
new Thread(() -> {Systemoutprintln("hello word!");})start();
() -> {Systemoutprintln("hello word!");}这句语句其实就是runnable接口的实现对象,
编译器会根据函数需要实现的接口去隐式转换,Thread的构造方法需要传递Runnable接口的实现类,所以new Thread(() -> {Systemoutprintln("hello word!");})start();相当于
new Thread((Runnable)() -> {Systemoutprintln("hello word!");})start();
其中()是匹配接口中的无参函数,因为Runnable接口中run方法为无参所以是()
->指明前面是传入参数,后面是函数体
有了lambda就能写出更加漂亮的代码,以及更少的工作量,实现一个方法的接口用匿名内部类的话看起来是冗余代码了
纯手打望采纳
匿名函数(Anonymous Function)是表示“内联”方法定义的表达式。匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型。匿名函数转换的计算取决于转换的目标类型:如果是委托类型,则转换计算为引用匿名函数所定义的方法的委托;如果是表达式树类型,则转换将计算以对象结构形式表示方法结构的表达式树。
匿名函数有两种语法风格:Lambda表达式(lambda-expression)和匿名方法表达式(anonymous-method-expression)。在几乎所有的情况下,Lambda表达式都比匿名方法表达式更为简介具有表现力。但现在C#语言中仍保留了后者,为了向后兼容。
Lambda表达式:
async可选 (匿名的函数签名)=> (匿名的函数体)
匿名方法表达式:
async可选 delegate (显式的匿名函数签名) 可选{代码块}
其中匿名的函数签名可以包括两种,一种是隐式的匿名函数签名另一种是显式的匿名函数签名:
隐式的函数签名:(p)、(p1,p1)
显式的函数签名:(int p)、(int p1,int p2)、(ref int p1,out int p2)
匿名的函数体可以是表达式或者代码块。
从上面我们可以看出,Lambda表达式的参数形式可以显式或者隐式类型化。在显式类型化参数列表中,每个参数的类型是显式声明的,在隐式类型化参数列表中,参数的类型是从匿名函数出现的上下文中推断出来的。
当Lambda表达式只有一个具有隐式类型化参数的时候,参数列表可以省略圆括号,也就是说:
(参数) => 表达式
可以简写为
参数 => 表达式
一些匿名函数的示例
x => x + 1 //隐式的类型化,函数体为表达式x => {return x + 1;} //隐式的类型化,函数体为代码块
(int x) => x + 1 //显式的类型化,函数体为表达式
(int x) => {return x + 1;} //显式的类型化,函数体为代码块
(x , y) => x y //多参数
() => ConsoleWriteLine() //无参数
async (t1 , t2) => await t1 + await t2 //异步
delegate (int x) {return x + 1;} //匿名函数方法表达式
delegate {return 1 + 1;} //参数列表省略
Lambda表达式和匿名方法表达式的区别:
当没有参数的时候,匿名方法表达式允许完全省略参数列表,从而可以转换为具有任意值参数列表的委托类型,Lambda表达式则不能省略参数列表的圆括号()。
Lambda表达式允许省略和推断类型参数,而匿名方法表达式要求显式声明参数类型。
Lambda表达式主体可以为表达式或者代码块,而匿名方法表达式的主体必须为代码块。
只有Lambda表达式可以兼容到表达式树类型。
函数是一组一起执行一个任务的语句。每个 C++ 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。
您可以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的。
C++ 标准库提供了大量的程序可以调用的内置函数。例如,函数 strcat() 用来连接两个字符串,函数 memcpy() 用来复制内存到另一个位置。
函数还有很多叫法,比如方法、子例程或程序,等等。
C++ 中的函数定义的一般形式如下:
return_type function_name( parameter list ){ body of the function}
在 C++ 中,函数由一个函数头和一个函数主体组成。
下面列出一个函数的所有组成部分:
返回类型: 一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的 *** 作而不返回值,在这种情况下,return_type 是关键字 void。
函数名称: 这是函数的实际名称。函数名和参数列表一起构成了函数签名。
参数: 参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
函数主体: 函数主体包含一组定义函数执行任务的语句。
实例
以下是 max() 函数的源代码。该函数有两个参数 num1 和 num2,会返回这两个数中较大的那个数:
// 函数返回两个数中较大的那个数
int max(int num1, int num2)
{
int result;
if (num1 > num2) result = num1;
else result = num2;
return result;
}
return_type function_name( parameter list );
int max(int num1, int num2);
int max(int, int);
创建 C++ 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。例如:
实例
#include <iostream>
using namespace std;
int max(int num1, int num2);
int main()
int a = 100; int b = 200; int ret;
// 调用函数来获取最大值
ret = max(a, b);
cout << "Max value is : " << ret << endl;
return 0;
}
// 函数返回两个数中较大的那个数
int max(int num1, int num2)
{
int result;
if (num1 > num2) result = num1;
else result = num2;
return result;
}
把 max() 函数和 main() 函数放一块,编译源代码。当运行最后的可执行文件时,会产生下列结果:
Max value is : 200
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
当调用函数时,有两种向函数传递参数的方式:
调用类型 描述
传值调用 该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。
指针调用 该方法把参数的地址复制给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
引用调用 该方法把参数的引用复制给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
默认情况下,C++ 使用传值调用来传递参数。一般来说,这意味着函数内的代码不能改变用于调用函数的参数。之前提到的实例,调用 max() 函数时,使用了相同的方法。
参数的默认值
当您定义一个函数,您可以为参数列表中后边的每一个参数指定默认值。当调用函数时,如果实际参数的值留空,则使用这个默认值。
这是通过在函数定义中使用赋值运算符来为参数赋值的。调用函数时,如果未传递参数的值,则会使用默认值,如果指定了值,则会忽略默认值,使用传递的值。请看下面的实例:
实例
#include <iostream>
using namespace std;
int sum(int a, int b = 20)
{
int result; result = a + b;
return (result);
}
int main()
int a = 100; int b = 200; int result;
// 调用函数来添加值
result = sum(a, b);
cout << "Total value is :" << result << endl;
// 再次调用函数
result = sum(a);
cout << "Total value is :" << result << endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Total value is :300
Total value is :120
Lambda 函数与表达式
C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。
Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。
[capture](parameters)->return-type{body}
例如:
[](int x, int y){ return x < y ; }
如果没有返回值可以表示为:
[capture](parameters){body}
例如:
[]{ ++global_x; }
在一个更为复杂的例子中,返回类型可以被明确的指定如下:
[](int x, int y) -> int { int z = x + y; return z + x; }
本例中,一个临时的参数 z 被创建用来存储中间结果。如同一般的函数,z 的值不会保留到下一次该不具名函数再次被调用时。
如果 lambda 函数没有传回值(例如 void),其返回类型可被完全忽略。
在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。 与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:
[] // 没有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&] // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=] // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x] // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。
另外有一点需要注意。对于[=]或[&]的形式,lambda 表达式可以直接使用 this 指针。但是,对于[]的形式,如果要使用 this 指针,必须显式传入:
[this]() { this->someFunc(); }();
以上就是关于Java匿名类可以用Lambda写,但是如果需要实现多个方法怎么写呢全部的内容,包括:Java匿名类可以用Lambda写,但是如果需要实现多个方法怎么写呢、java 8 新特性中p->p.setLastName("Doe"));、c#lambda表达式 和匿名函数的区别等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)