泛型2(lambda表达式/参数绑定)

lambda 表达式:

Lambda表达式完整的声明格式如下:

[capture list] (params list) mutable exception-> return type { function body }

各项具体含义如下:

  1. capture list:捕获外部变量列表
  2. params list:形参列表
  3. mutable 指示符:用来说用是否可以修改捕获的变量
  4. exception:异常设定
  5. return type:返回类型
  6. function body:函数体

我们这里先不讨论 exception

我们可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体:

 1 #include <iostream>
 2 using namespace std;
 3
 4 int main(void){
 5     auto f = [] { return 42; };
 6     auto g = [] {int a = 1; a++; return a;};
 7     cout << f() << endl;//42
 8     cout << g()  << endl;//2
 9     return 0;
10 }

注意:在 lambda 中忽略括号和参数列表等价于指定一个空参数列表。在此列表中,当调用 f 时,参数列表是空的。如果忽略返回类型,lambda 根据函数体中的代码推断出返回类型。在 c++11 标准中,如果 lambda 的函数体包含任何单一 return 语句之外的内容,且未指定返回类型,则返回 void。不过在很多编译器中好像只要有 return 语句就会返回编译器推断的类型~

向 lambda 传递参数:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 using namespace std;
 5
 6 int main(void){
 7     vector<string> words = {"df", "fsl", "feg", "laf", "fsfl", "jfsoe"};
 8     stable_sort(words.begin(), words.end(),
 9                 [](const string &a, const string &b)
10                     {return a.size() < b.size();});
11     for(const auto &indx : words){
12         cout << indx << " ";
13     }
14     cout << endl;//df fsl feg laf fsfl jfsoe
15     return 0;
16 }

其中,空捕获列表表名此 lambda 不使用它所在函数中的任何局部变量。当 stable_sort 需要比较两个元素时,它就会调用给定的这个 lambda 表达式。

注意:通常,实参和形参类型必须匹配。但与普通函数不同,lambda 不能有默认参数。因此,一个 lambda 调用的实参数目永远与形参数目相等。一旦形参初始化完毕,就可以执行函数体了。

使用捕获列表 / find_if / for_each:

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 int gg = 2;
 7
 8 int main(void){
 9     vector<string> words = {"df", "fsl", "feg", "laf", "fsfl", "jfsoe"};
10     int sz1 = 3, sz2 = 2;
11     auto wc = find_if(words.begin(), words.end(),
12         [sz1, sz2](const string &a){//捕获sz1,sz2变量
13             return a.size() >= sz1 || a.size() >= sz2;//使用捕获的变量sz1,sz2
14         });//find_if返回第一个满足谓词条件的迭代器
15
16     cout << *wc << endl;//df
17     auto count = words.end() - wc;
18     cout << count << endl;//6
19
20     const int sz = 3;
21     auto indx = find_if(words.begin(), words.end(),
22         [](const string &a){
23             return a.size() >= sz;//常量可以不捕获就使用!!!
24         });
25
26     int len = 3;
27     // auto indx = find_if(words.begin(), words.end(),
28         // [](const string &a){
29             // return a.size() >= len;//错误,len变量没有被捕获不能使用
30         // });
31
32     static int b = 3;
33     auto id = find_if(words.begin(), words.end(),
34         [](const string &a){
35             return a.size() >= b || a.size() >= gg;//static变量和lambda所在函数之外的变量也可以直接使用
36         });
37
38     for_each(wc, words.end(),
39         [](const string &s){//对迭代器区间的每个元素都调用一遍谓词
40             cout << s << " ";
41         });//df fsl feg laf fsfl jfsoe
42     cout << endl;
43
44     return 0;
45 }

注意:这里的 lambda 表达式是作为 find_if 和 for_each 的谓词的,lambda 的形参列表接受这两个函数的输入并对输入序列中的元素调用谓词,返回一个能用作条件的值

捕获列表捕获其所在函数中的局部变量,使它们能在 lambda 函数体中被使用

形参列表中的参数也能直接在 lambda 函数体中使用

发现函数体中的 const 变量能直接在 lambda 函数体中直接使用

static 变量和 lambda 函数之外定义的变量也可以直接使用

lambda 捕获和返回:

当定义一个 lambda 时,编译器生成一个与 lambda 对应的新的(未命名的)类类型。当向一个函数传递一个 lambda 时,同时定义了一个新类型和该类型的一个对象:传递的参数就是此编译器生成的类类型的未命名对象。类似的,当使用 auto 定义一个用 lambda 初始化的变量时,定义了一个从 lambda 生成的类型的对象。

默认情况下,从 lambda 生成的类都包含一个对应 lambda 所捕获的变量的数据成员。类似任何普通类的数据成员,lambda 的数据成员也在 lambda 对象创建时就被初始化。

值捕获:

类似于参数传递,变量的捕获方式也可以是值或引用。前面的代码我们用的都是值捕获。与传值参数类似,采用值捕获的前提是变量可拷贝。与参数不同的是被捕获的变量的值是在 lambda 创建时拷贝的,而不是调用时拷贝:

 1 #include <iostream>
 2 #include <fstream>
 3 using namespace std;
 4
 5 int main(void){
 6     size_t v1 = 42;
 7     auto f = [v1]{return v1;};//将v1拷贝到名为f的可调用对象
 8     v1 = 0;
 9     auto j = f();
10     cout << j << endl;//42 j 保存了我们创建它时v1的拷贝
11
12     ofstream cc;
13     // auto g = [os]{};//错误,ostream类型的对象是不可拷贝的,不能用值捕获
14     auto g = []{cout << 1;};//cout定义在iostream头文件中,可以直接使用
15
16     return 0;
17 }

注意:由于被捕获的变量的值是在 lambda 创建时拷贝,因此随后对其修改不会影响到 lambda 内对应的值

不能被拷贝的对象不能用于 lambda 值捕获

引用捕获:

引用捕获和一般的引用传参行为类似

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 using namespace std;
 5
 6 void fun(void){
 7     size_t v1 = 42;
 8     auto f = [&v1]{return v1;};//对v1引用捕获
 9     v1 = 0;
10     auto j = f();
11     cout << j << endl;//0
12 }
13
14 void biggies(vector<string> &words, vector<string>::size_type sz, ostream &os = cout, char c = ‘ ‘){
15     for_each(words.begin(), words.end(),
16         [&os, c](const string &s){//IO对象只能引用捕获
17             os << s << c;
18         });//fjks fsl fjsl fiwo
19 }
20
21 int main(void){
22     fun();
23     vector<string> v = {"fjks", "fsl", "fjsl", "fiwo"};
24     biggies(v, 4);
25
26     return 0;
27 }

注意:使用捕获一个引用(迭代器,指针)变量时,必须确保被引用的对象在 lambda 执行的时候是存在的

lambda 捕获的都是局部变量,这些变量在函数接受后就不复存在了

如果 lambda 可能在函数结束后执行,捕获的引用指向的局部变量已经消失

对于不能拷贝的对象,如 IO 对象,必须采用引用捕获

隐式捕获:

除了显示列出我们希望使用的来自所在函数的变量之外,还可以让编译器根据 lambda 体中代码来判断我们要使用哪些变量。为了指示编译器判断捕获列表,应该在捕获列表中写一个 & 或 =。& 告诉编译器采用引用的捕获方式,= 则表示值捕获方式:

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 void biggies(vector<string> &words, vector<string>::size_type sz, ostream &os = cout, char c = ‘ ‘){
 7     for_each(words.begin(), words.end(),//如果我们希望对一部分变量采用值捕获,对其它变量采用引用捕获,可以混合使用隐式捕获和显示捕获
 8         [&, c](const string &s){//os隐式捕获,引用捕获方式;c显示捕获,值捕获方式
 9             os << s << c;
10         });//df fsl feg laf fsf
11
12     cout << endl;
13
14     for_each(words.begin(), words.end(),
15         [=, &os](const string &s){//os显示捕获,引用捕获方式;c隐式捕获,值捕获方式
16             os << s << c;
17         });//df fsl feg laf fsf
18
19     cout << endl;
20
21     int cc = 1;
22     for_each(words.begin(), words.end(),
23         [&, cc, c](const string &s)mutable{//错误,两个都使用隐式捕获,编译器不能区分
24             os << cc++ << c << s << endl;
25         });
26
27     // for_each(words.begin(), words.end(),
28     //     [cc, c, &](const string &s)mutable{//只能捕获列表中第一个元素可以使用隐式捕获
29     //         os << cc++ << c << s << endl;
30     //     });
31
32     // for_each(words.begin(), words.end(),
33     //     [=, =](const string &s)mutable{//只能有一个捕获是隐式的
34     //         cout << cc++ << c << s << endl;
35     //     });
36 }
37
38 int main(void){
39     int sz = 3;
40     vector<string> words = {"df", "fsl", "feg", "laf", "fsfl", "jfsoe"};
41     auto wc = find_if(words.begin(), words.end(),
42         [=](const string &s){//sz为隐式捕获,值捕获方式
43             return s.size() >= sz;
44         });
45     cout << *wc << endl;//fsl
46
47     biggies(words, words.size());
48
49     return 0;
50 }

注意:当我们混合使用隐式捕获和显示捕获时,捕获列表中的第一个元素必须是 & 或 =。此符号指定了默认捕获方式为引用或值

当混合使用隐式捕获和显示捕获时,显示捕获的变量必须使用与隐式捕获不同的方式。即,如果隐式捕获是引用方式,则显示捕获必须采用值方式。反之亦然~

捕获列表中只能有一个元素采用隐式捕获,且该变量必须是捕获列表中的第一个元素

可变 lambda:

 1 #include <iostream>
 2 using namespace std;
 3
 4 int main(void){
 5     int x = 1;
 6     // auto gel = [x](){
 7     //     x++;//这里的x不能改变
 8     //     return x;
 9     // };
10
11     // auto gel = [x] mutable{//错误,加了mutable关键字后不能省略参数列表
12     //     x++;
13     //     return x;
14     // };
15
16     auto gel = [x] () mutable{
17         return ++x;
18     };
19     cout << gel() << endl;//2
20
21     const int y = 1;
22     // auto cc = [y] () mutable{
23     //     return ++y;//虽然加了mutable关键字,但y本身是const变量,所以不能修改
24     // };
25     //即在显示值捕获中,拷贝得到的形参仍然是const的
26
27     auto cc = [&x] {
28         return ++x;//对于引用捕获,如果引用绑定的是一个非const对象,则不加mutable也是可变的
29     };
30
31     // auto cb = [&y] {
32     //     return ++y;//y是一个const对象,不可变
33     // };
34
35     auto cd = [&x] () mutable{
36         return ++x;
37     };
38     cout << gel() << endl;//3
39
40     // auto ce = [&y] () mutable{
41     //     return ++y;//加了mytable,但y是const的,不可变
42     // };
43
44     return 0;
45 }

注意:对于值捕获,若没加 mutalbe 关键字,则其捕获变量一定是不可变的,加了 mutable 关键字则取决于对应变量在函数中声明是否是 const 的。而引用捕获变量是否可变与 mutable 无关,只取决于绑定的对象是否是 const 的。

指定 lambda 返回类型:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <array>
 4 using namespace std;
 5
 6 int main(void){
 7     array<int, 10> a = {1, -1, 2, -3, 4, -459, -94};
 8     //transform接受3个迭代器和一个可调用对象.前两个迭代器表输入序列,第三个迭代器表目标位置。
 9     //算法对输入序列中每个可调用元素调用可调用对象,并将结果写入目的位置
10     transform(a.begin(), a.end(), a.begin(),
11         [] (int i) {
12             return i < 0 ? -i : i;
13         });
14
15     //如果我们将上面代码改写为看起来等价的if语句,按照c++11标准会编译错误,因为lambda函数体中如果含有多个return语句的话编译器推断是返回void的
16     //不过我用g++11通过了编译欸~
17     transform(a.begin(), a.end(), a.begin(),
18         [] (int i) {
19             if(i < 0) return -i;
20             else return i;
21         });
22
23     //符合c++11的标准的写法
24     transform(a.begin(), a.end(), a.begin(),
25         [] (int i) -> int {
26             if(i < 0) return -i;
27             return i;
28         });
29
30     return 0;
31 }

注意:对于不能正确推断出返回类型的情况,必须使用尾置返回类型指明返回值的类型

在 lambda 中不能访问 protected 成员:

 1 #include <cstdio>
 2
 3 class A{
 4 protected:
 5     void Somefunc(){
 6         printf("Hello world!");
 7     }
 8 };
 9
10 class B{
11 public:
12     template<class F>
13     void D(F func){
14         func();
15     }
16 };
17
18 class E : public A{
19 public:
20     void Myfunc(){
21         A::Somefunc(); // works
22         B C;
23         // C.D([&](){//错误,lambda的作用域是单独的,不能在其中调用受保护的类成员
24         //     A::Somefunc(); // not works
25         // });
26
27         C.D([&](){
28             this->Somefunc(); //我们可以利用继承的特性直接使用protected成员嘛~
29         });
30     }
31 };
32
33 int main(){
34     E F;
35     F.Myfunc();
36
37     return 0;
38 }

参考:https://segmentfault.com/q/1010000000479642

参数绑定:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 using namespace std;
 5
 6 int main(void){
 7     int sz = 5;
 8     vector<string> v = {"jkfd", "jfkls", "fj", "fjslf", "fjsljfslf"};
 9     auto cnt = find_if(v.begin(), v.end(),
10         [sz] (const string &s) {
11             return s.size() > sz;
12         });
13
14     cout << *cnt << endl;//fjsljfslf
15
16     return 0;
17 }

对于 sort 中的谓词通常我们可以将其写成一个单独的可调用函数,但是对于上面代码中 find_if 中的谓词,如果我们不将 sz 定义成全局变量显然不能将其写成一个单独函数的形式。因为 find_if 接受的是一个一元谓词,这意味着我们不能给其谓词函数不能有两个形参~

标准库 bind 函数:

我们可以通过使用一个名为 bind 的标准库函数来解决上面提到的问题,它定义在 functional 头文件中。可以将 bind 函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来 "适应" 原对象的参数列表。调用 bind 的一般形式为:

auto newCallable = bind(callable, arg_list);

其中,newCallable 本身是一个可调用对象,arg_list 是一个逗号分隔的参数列表,对于给定的 calloble 的参数。即,当我们调用 newCallable 时,newCallable 会调用 callable,并传递给它 arg_list 中的参数。

arg_list 中的参数可能包含形如 _n 的名字,其中 n 是一个整数。这些参数是 "占位符",表示 newCallable 的参数,它们占据了传递给 newCallable 的参数的 "位置"。数值 n 表示 生成的可调用对象中参数的位置:_1 为 newCallable 的第一个参数,_2 为第二个参数,依此类推。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 #include <functional>
 5 using namespace std;
 6
 7 bool check_size(const string &s, int sz){
 8     return s.size() >= sz;
 9 }
10
11 int main(void){
12     int sz = 5;
13     vector<string> v = {"jkfd", "jfkls", "fj", "fjslf", "fjsljfslf"};
14     auto check6 = bind(check_size, std::placeholders::_1, sz);//_n都定义在命名空间placeholders中,且此命名空间又定义在命名空间std中
15     //check6是一个可调用对象,接受一个string类型的参数
16     auto cnt = find_if(v.begin(), v.end(), check6);
17
18     cout << *cnt << endl;//fjslf
19
20     return 0;
21 }

注意:此处 bind 调用只有一个占位符,表示 check6 只接受单一参数。占位符出现在 args_list 的第一个位置,表示 check6 的此参数对应 check_size 的第一个参数。此参数是一个 const string&。因此,调用 check6 必须传递给他一个 string 类型的参数,check6 会将此参数传递给 check_size

_n 都定义在命名空间 placeholders 中,且此命名空间又定义在命名空间 std 中。我们也可以通过 using 来声明:

using std::placeholders::_1;

不过这种声明意味着我们对每个占位符名字都必须提供一个单独的 using 声明。我们可以使用另外一种更方便一些的声明方式:

using namespace namespace_name;

则所有来自 namespace_name 中定义的名字我们都可以直接在程序中直接使用:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 #include <functional>
 5 using namespace std;
 6
 7 using namespace std::placeholders;
 8
 9 bool check_size(const string &s, int sz){
10     return s.size() >= sz;
11 }
12
13 int main(void){
14     int sz = 5;
15     vector<string> v = {"jkfd", "jfkls", "fj", "fjslf", "fjsljfslf"};
16     auto check6 = bind(check_size, _1, sz);
17     auto cnt = find_if(v.begin(), v.end(), check6);
18
19     cout << *cnt << endl;//fjslf
20
21     return 0;
22 }

注意:使用这种方式需要注意命名冲突问题

bind 参数顺序问题:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <array>
 4 #include <functional>
 5 using namespace std;
 6 using namespace std::placeholders;
 7
 8 bool cmp(const string &s1, const string &s2){
 9     return s1.size() < s2.size();
10 }
11
12 int main(void){
13     array<string, 5> a = {"fjls", "jf", "jflsjdf", "jfslk", "jfsljflsfjsjfsl"};
14
15     stable_sort(a.begin(), a.end(), cmp);
16     for(const auto &indx : a){
17         cout << indx << " ";
18     }
19     cout << endl;//jf fjls jfslk jflsjdf jfsljflsfjsjfsl
20
21     auto rcmp = bind(cmp, _2, _1);//_2对应cmp的第一个形参,_1对应cmp的第二个形参
22     stable_sort(a.begin(), a.end(), rcmp);//传入的第一个参数绑定的是_1,第二个参数绑定_2,即实际上调用的是bind(_1, _2)
23     for(const auto &indx : a){
24         cout << indx << " ";
25     }
26     cout << endl;//jfsljflsfjsjfsl jflsjdf jfslk fjls jf
27     return 0;
28 }

注意:在 stable_sort(a.begin(), a.end(), rcmp);的调用中,传入 rcmp 中的第一个参数对应 _1,第二个参数对应 _2,即是按照占位符的数字大小顺序对应的,而不是按照占位符在 rcmp 参数列表的顺序对应的。但是 rcmp 中的参数对应 cmp 中的形参列表是按照参数位置顺序一一对应的。因此,在第一个调用中,当 stable_sort 需要比较两个元素 A 和 B 时,它会调用 cmp(A, B)。在第二个 stable_sort 调用时,传递给 cmp 的参数就被交换过来了。即比较 A,B 两个元素时相当于调用的 cmp(B, A)。因此,在第一次 stable_sort 调用的结果是对 a 中字符串按长度升序排列,而第二次调用 stable_sort 调用的结果是对 a 中的字符串按长度降序排列~

绑定引用参数:

默认情况下,bind 的那些不是占位符的参数被拷贝到 bind 返回的可调用对象中:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 #include <functional>
 5 using namespace std;
 6 using namespace std::placeholders;
 7
 8 ostream &print(ostream &os, const string &s, char c){
 9     os << s << c;
10 }
11
12 int main(void){
13     vector<string> v = {"fjs", "fjsl", "fjslf", "fjlsjf"};
14     ostream &os = std::cout;
15     const char c = ‘ ‘;
16
17     for_each(v.begin(), v.end(),
18         [&os, c] (const string &s) {
19             os << s << c;
20         });
21     cout << endl;
22
23     //用bind实现同样的功能
24     // for_each(v.begin(), v.end(), bind(print, os, _1, c));//错误,非占位符默认是值传递的,os是IO对象,不能拷贝
25     for_each(v.begin(), v.end(), bind(print, ref(os), _1, c));//函数ref返回一个对象,包含给定的引用,次对象是可以拷贝
26
27     return 0;
28 }

注意:对于不能拷贝的对象,需要通过 ref 函数才能用作 bind 的非占位符参数

函数 ref() 返回一个对象,包含给定的引用,此对象是可以拷贝的。标准库中还有一个 cref 函数,生成一个保存 const 引用的类。ref 和 cref 定义在头文件 functional 中。

原文地址:https://www.cnblogs.com/geloutingyu/p/8335230.html

时间: 2024-10-10 03:54:04

泛型2(lambda表达式/参数绑定)的相关文章

JDK1.8新特性(二): Lambda表达式 (参数列表) -&gt; { } 和函数式接口@FunctionalInterface

Lambda表达式 二:简介 JDK的升级的目的有以下几个:增加新的功能.修复bug.性能优化.简化代码等几个方面,Lambda表达式就是属于简化代码,用于简化匿名实现类,提供一种更加简洁的写法.Lambda表达式在Swift语言中称之为代码块,Lambda表达式可以认为是一种特殊的接口,该接口必须只有一个抽象方法. 语法 (参数类型 参数名, 数参数类型 参数名2...) -> { // code }; 小括号()中的内容就是方法中的参数列表包括参数类型.参数名,其中参数类型是可以省略的,当参

ASP.NET MVC学前篇之Lambda表达式、依赖倒置

前言 随着上篇文章的阅读,可能有的朋友会有疑问,比如(A.Method(xxx=>xx>yy);)类似于这样的函数调用语句,里面的xxx=>xx>yy这些到底是怎么用的? 依赖倒置原则的实现也会在本篇幅的最后来粗略的讲解一下. 本篇没有核心的主题,如果说要强制定义的话就是这些内容都是基础知识,是为了后续学习MVC框架做铺垫. 1 Lambda Lambda表达式在日常的开发中很常见,使用Lambda表达式可以自由的定义函数体并且精简代码量,那么Lambda表达式是什么呢? Lamb

C# 匿名函数和Lambda 表达式

匿名函数是一个"内联"语句或表达式,可在需要委托类型的任何地方使用. 可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数. 共有两种匿名函数,以下主题中分别讨论了这些函数: Lambda Expressions (C# Programming Guide). ' data-guid="7df86c4348dea57abb774138a7de05b8">Lambda 表达式(C# 编程指南) . 匿名方法(C# 编程指南) 说明

Java8新特性Stream API与Lambda表达式详解(1)

1 为什么需要Stream与Lambda表达式? 1.1  为什么需要Stream Stream作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream.Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggr

C++ 11 Lambda表达式、auto、function、bind、final、override

接触了cocos2dx 3.0,就必须得看C++ 11了.有分享过帖子:[转帖]漫话C++0x(四) —- function, bind和lambda.其实最后的Lambda没太怎么看懂. 看不懂没关系,会用就行.可惜是连用都要思考半天.其实,查找根源是定义没有搞明白. 以后买东西,用之前,先看说明书才是必要的. ---------------------------------开始正文粘贴----------------------------------------- 一.Lambda表达式

Java SE 8 for the Really Impatient读书笔记——Java 8 Lambda表达式

1. lambda表达式的语法 语法十分简单:参数->主体 1.1 参数 可以是零个参数,一个参数,也可以是多个参数,参数可以指定类型,在编译器可以推导出参数类型的情况下,也可以省略参数类型. 两个参数的例子: (String first, String second)-> Integer.compare(first.length(), second.length()) 0个参数的例子: () -> { for (int i = 0; i < 1000; i++) doWork()

C#中Lambda表达式总结

在C#的语法中有一种比较特殊的写法,叫做Lambda表达式,这种表达式的写法在于你查询数据的时候直接是使用以下箭头的形式来表示查询语句的:=>.例如,我们要查找学生的List<Student>集合中班级编号为1001的所有学生数据,我们即可用Studentlist.Where(t=>t.ClassCode='1001')语句来直接完成,无需再写繁琐的foreach语句或者for循环.Lambda表达式的运算符即为=>. 一.Lambda表达式定义 Lambda表达式实际上是一

java lambda表达式学习笔记

lambda是函数式编程(FP,functional program),在java8中引入,而C#很早之前就有了.在java中lambda表达式是'->',在C#中是‘=>’. 杜甫说:射人先射马,擒贼先擒王.学习一个库要学习它的入口类.lambda的入口类是Stream,一看Stream中的函数就会发现Function,Predicate等lambda元素. 一.几个概念     函数式接口 Functional Interface,除了static和default类型的方法外,只有一个函数

Java8函数式编程 (一) 数据流和lambda表达式

JDK 1.8中引入了函数式编程(functional programming,FP),如果您已习惯OOP,一定会感到困惑:什么是函数式编程?这样的编程模式有什么好处? 本文将通过简单的实例令读者对函数式编程有一个大体的了解. 我们知道OOP是以类为基础的,程序中必须首先抽象和定义class.那么FP创建的基础是什么?或者说在Java 8中,至少需要了解什么知识点才能实现基本的函数式编程呢? 本文将首先介绍在Java 8中使用FP所需的基本知识点: Lambda表达式 数据流 基本实例 Map<