笑话/JDK8的新特性——Lambda表达式
JDK8已经发布快4年的时间了FEpS7wRnuH4Gb,C8j5z7t78Ij80I现在来谈它的新特性显得略微的有点“不合时宜”2l14Lq4e。pHUaQOOSIiUG尽管JDK8已不再“新”WWe555HO7d3B71,2c25ilfGpK但它的重要特性之一——Lambda表达式依然是不被大部分开发者所熟练运用CM8449lAZe,gq0148u甚至不被开发者所熟知NF2zU2。RL2NIrS1Li36bI   国内的开发环境大家都知道E779n3ekR49M,6329DCgK8hGFl有各种的老项目8tw450p,q0Ox0有各种各样的发布风险H5JY3lqX2Y8D,2X4HuSs5o68让公司以及项目组对新的技术往往望而却步09WK088Wo433,LnzhA5Zd有公司甚至时至今日还在使用JDK6来进行项目开发9mkV6bZYf,S10iv0318Ll这导致了在很多技术的选择上受到了很大限制A3Z2bp1I,B77SfsT进而不能跟随时代的脚步使得项目甚至公司一步一步走向衰落X9E78b08。RI6n60HD9   本文简单认识JDK8的重要新特性之一——Lambda表达式y073q。BHB144 在JDK8之前gPId221LdI,MmQ016DDrJava是不支持函数式编程的9TTOKsp,8Sa2lWxaDbVU所谓的函数编程isDANWI,DkOrOmk即可理解是将一个函数(也称为“行为”)作为一个参数进行传递qw7j9ac757rx。mRd74wvkbnu2通常我们提及得更多的是面向对象编程j19j2S3,CBXgq0l面向对象编程是对数据的抽象(各种各样的POJO类)bdmf976,Xlg9ss而函数式编程则是对行为的抽象(将行为作为一个参数进行传递)r043RI。j63KmCEBYXW1X2在JavaScript中这是很常见的一个语法特性MH9ch,CpcUg8j但在Java中将一个函数作为参数传递这却行不通EzhxjSy2JoM,vYj94287P好在JDK8的出现打破了Java的这一限制9qs5W。F7HdPxkB7836 认识Lambda表达式   首先来引入一个示例aKHsVgKS144,38kV7GutG1mo不知给是否有在IDEA编写代码的经历5JbRs5mZ0,qS2Wsxrqii7Mkc如果在JDK8的环境下如下所示按照Java传统的语法规则编写一个线程vu35nqUt7c。9Cc9zzz9 1 new Thread(new Runnable() {u6e0h8i8BM4zO YY3DM7Y6xSR0gc2    @OverridegN7FE L9dn7kq3 public void run() {hlz7zq0PQ a5854G4 System.out.println("Hello World!");MoiQCM 9L84HQy5    }7iZuvxz3dn19 g71M46 });   IDEA会给出提示可以使用Lambda表达式替换9q8Wa203377Rfq。dru2YhwO9KL622   使用Lambda表达式则只需要使用一句话就可代替上面使用匿名类的方式0y7fD0bc。kZ134A new Thread(() -> System.out.println("Hello World!"));   在这个例子中rC4K9d2I1V,0FZ47l6gjuO0hu传统的语法规则w73tE9W,1L073x3lR8我们是将一个匿名内部类作为参数进行传递uAl0M,tIj6nzgKQ89c我们实现了Runnable接口fUlNgI74015,oDdb93gm8并将其作为参数传递给Thread类3dOlfFuG4APG9,57l5F这实际上我们传递的是一段代码DngJdQZfRT1hu,0ZcKSsxR也即我们将代码作为了数据进行传递W8LS8M,4yWl4aZ7YJI1这就带来许多不必要的“样板代码”ZA55QSfPX4。m4KtyBP8T1Njl   Lambda表达式一共有三部分组成wznUzC5O6S:xu18XYVbUYCp   后面的示例中我们会详解这个结构S6576l96,1l8GKHpu12包括有无参数BTap7qZ4F59G9W,IZFYFH804cQ0有无返回值的问题R6a5C4873V4。LWm0KH 那么这个看起来奇奇怪怪的不太像Java的语法规则0NEbbdM49,BH4NB其本身含义到底什么呢378p7c?9N2u7cc2jSRCp这也是开始困扰我的问题r2Hk9jM6aDB4,85D6h2x4r8什么时候在什么场景下可以使用Lambda表达式zYS2qOZA9Y。599PM   能够接收Lambda表达式的参数类型YekSpggsS,H9444eH6是一个只包含一个方法的接口N7g37i3JzI。klL7OYlxNI只包含一个方法的接口称之为“函数接口”rKlq7UHTEK。PC307   例如上面创建一个线程的示例77Dgm39F,r9Ko2R15C7pWRunnable接口只包含一个方法oHL9H161Jxn,vDF34z9所以它被称为“函数接口”Ck0d2wvPlcbYc5,J1kf4Dv所以它可以使用Lambad表达式来代替匿名内部类EMQNZ8K3vwvM2a。4TjyPQyWJ0K1n根据这个规则WfF4i8BY6u3d1,G6FX9X631tKu我们试着来写一个函数接口40paGMSFgoJ,789k3b0H并使用Lambda表达式作为参数传递810SNana。jHoaB8 1 package com.coderbuff.custom;H6QERY70PWh1 W5UD5B1o02 MedfPBwb2UCmn 1LEFe92wGzNES33 /**4PB164VaFW 76ay0KG9eW4 * 函数接口Yp3p2aUkp:lhvs4f5TeY662只有一个方法的接口uP1O8。32mB21K作为Lambda表达式的类型KlY16L2a3f0ON 0M9R2r5 * Created by Kevin on 2018/2/17.Hr54icapF vZvzznOM6 */CJ7y0df b5cKMvm9ELFoP7 public interface FunctionInterface {1k1XVP751cjD 40A0b418 void test();3II6K5LM2XQ K4Py6yV4aw9 }   测试whcRL6e02:WtrWWuhW4ht4d6 1 package com.coderbuff.custom;gAr1Cp6k084VA FLArMli 2 1if512TJ30 rQLC8Y9Dh0B0v 3 import org.junit.Test;aJrZkri 1KFmDw02tk 4 zVx081VW972Mj 8gXBHwHG 5 /**4y9xqw0J krkVJ 6 * 函数接口测试8fqXfpK01Dy 12RSdo613e944z 7 * Created by Kevin on 2018/2/17.9Jn8e5 5e7k910MEWVN 8 */qBgoG 2F59iI36QwGf1I 9 public class FunctionInterfaceTest {a3C48sMEev0wF 3QLwTTIl410 DXTK7 XstgHp11    @TestoJOe0 yZ2xL12 public void testLambda() {RGDGSBrMW5488 279wSdV13 func(new FunctionInterface() {4Z6W1EFYTz6z0O 9sogV14            @OverrideMl1V780t4iI5f 849e5E85YYDd15 public void test() {6TWKVZn5 GT5xZlcybl5O16 System.out.println("Hello World!");q5kC6U Gc9Q2RVJ17            }89dt408 2WjJ567W8og18        });f8HtE6T4y DiJvUKYg22419 //使用Lambda表达式代替上面的匿名内部类02rmZR96e 58SAiC3VQPP4n20 func(() -> System.out.println("Hello World"));Pg03Lx6qG4cu z7Ug221    }0IhAD32689Mgj m466fcM522 Z8Gc1TY8cctU 37Z2fx9isi23 private void func(FunctionInterface functionInterface) {7dKEZ b602vZ2X8L24        functionInterface.test();4RXLfn j7GXZZDHUI25    }rA5w2Gm07HVit y40AxK26 }   可以看到9hZ5SUhXu,QZ92Rv638只要是一个接口中只包含一个方法D7Cr8,uKvxikX2EP5ZU则可以使用Lambda表达式wQ9t3oqHxGp4Z,KrcI396njxFM9J这样的接口称之为“函数接口”0oag1nk3r。knpz86CaWaNX   上面的函数接口比较简单不包含参数F3kbMjor2,qy3q0H2也不包含返回值ts441i。l95atj7Znb5I0A   我们再来修改FunctionInterface函数接口逐步加大Lambda表达式的难度——包含参数iFWCmhD9,YF7T164不包含返回值fC7684t8t。Gl1bdI8rc25xs 1 package com.coderbuff.custom;qvNG4Ds27p CH23cXa1S4X2 S6N62D30ZRAbl FR6X5te3 /**9kqph4tr CyuX3YO63HIF74 * 函数接口0x41O:8TH45864R0g2Wm只有一个方法的接口5t20wBrh88D。K0WKs110dk作为Lambda表达式的类型5D9C61de4 Zo02CI5MnZa5 * Created by Kevin on 2018/2/17.n2qq42V3Xr7klb P2P6m6 */0bQP77tTnWF nWRa1Je0CP7 public interface FunctionInterface {9YMi76 Q1GG7H58 void test(int param);WrLMm JrxAH33VJ6d9 }   测试QSDc39Shh1kr:1OzRN68S5vm5Hm 1 package com.coderbuff.custom;9XO7b 1aPRl48eVA25 2 05tIupl35M1M6v iJAy8567lJXj 3 import org.junit.Test;Ip0yAovvay 4mZqsp06 4 yOaO0t 0HSXQNI53N5 5 /**ZnEu569q 8lQ76z 6 * 函数接口测试AMGH835N2BWp I6H6Dqe 7 * Created by Kevin on 2018/2/17.4kzATTX yl3U4uWHI9CWR 8 */QOwWgwksAq4 NIzT91Flc7B 9 public class FunctionInterfaceTest {2yVLKX8GxY0 821jO8wh2ki310 U1ZBBo0gMw5 Dt929d5T11    @TestSDm15e5 40TEp82ivq1kj12 public void testLambda() {bakC6LEOc1P tZ5b304Cuzb13 //使用Lambda表达式代替匿名内部类9TabY PKmJw996GZI14 func((x) -> System.out.println("Hello World" + x));O6B1m4o28NDP OkrvR15    }1jZ5fgYVU4b9G g2ng6s5l16 vZ5QqL3GU71VTm UCfwlj8O22WA217 private void func(FunctionInterface functionInterface) {Wr6Q9487oS0 BTP9R18 int x = 1;t3JNZQtsMrn1 9iWv619        functionInterface.test(x);KpMr2iLOxo mHkv64cqtGk20    }41OMYfau1 9DBG6jPnjR5dz21 }   关注Lambda表达式“(x) -> Sysout.out.println("Hello World" + x)”49MGu365SF,z1q0phG8WCn左边传递的是参数uXcwnbpbuoV,J76n7UR8此处并没有指明参数类型FPERT,gW7V819因为它可以通过上下文进行类型推导35qNymlU,5H7FW7KdilcuP3但在有些情况下不能推导出参数类型(在编译时不能推导通常IDE会提示)38jeV7eUX,asnBkyv0此时则需要指明参数类型4BNbleKfjPAH7b。6hJvVqOhL8我个人建议UfqPKjXoMCrLq8,lJgQqk9jDRt任何情况下指明函数的参数类型T2Txriv。H0QfBIu3o   哪种情况不能推导出参数类型呢d7AZ31pyUXn?avhvF32Y84hh8就是函数接口是一个泛型的时候lP4rji7CFjho43。V3tTp 1 package com.coderbuff.custom;4CE83GQNZZ6m9x 9OHSn7F79m2 ZU3cyBQ3W9 C89rUB29VN2m23 /**9QE6sbb5ZA6U Hx7624 * 函数接口OU2D527H1q:bWgFb05zjT只有一个方法的接口D4F9jsNpF4。280tb作为Lambda表达式的类型20Nha1QD DyEJj5aY87kI05 * Created by Kevin on 2018/2/17.iKsYX EhL92YCU6 */20hYxPx85aB 3O457HNqz5M7 public interface FunctionInterface {yR30t8ti7 omlWJB8 void test(T param);pBrC9dNp 2wsaLskjS9 }    测试Dg01g2H6:eZ5cZarvi3I 1 package com.coderbuff.custom;1z9I0 q3z0Og6occ26nZ 2 P7VIL 1566W5El 3 import org.junit.Test;356WoTMfI6OZ 122pcblkpACYpJ 4 zF3mB6n3wenVw 86ltc8f05hiL2 5 /**mJz533S9EwwQ47 f7240D62AqA 6 * 函数接口测试3eji3T7nA1 kTZ7z2WdOyKWT 7 * Created by Kevin on 2018/2/17.L6rt40hi 7Wy8C 8 */2b0DAW5z3S3 Cc2izT5Va36hlo 9 public class FunctionInterfaceTest {Diyrt68 r44MyNlV910 e6oIck3q7cRpIK izig8nCz91Ri4h11    @Testb29E6CJTwN C7F4pUt9VDp812 public void testLambda() {yQ7zyEZ2a6J6 b3h2gu6vA37FD13 //使用Lambda表达式代替匿名内部类3Xvo1B12mmCa 9tz020614 func((Integer x) -> System.out.println("Hello World" + x));uH4k13j8vT Gm4ouQ8yIsM15    }yXAHg R13f0iNl6pd16 sHd9a qVVum417 private void func(FunctionInterface functionInterface) {xGm3fbj w00Vi3i18 int x = 1;oW4WM1mWM45 Z9mpnbgRymE7EE19        functionInterface.test(x);CT78o YLFjALSEz20    }kJ631splfmp j2ydw21 }   上面的示例提到了Lambda表达式的两种情况67pdTOowf87:tQPGg7tUIkbf   无参数mdV3LHOHxD8f,8D59H60H8cr无返回值3Y80k;1N8cH5630   有参数x3fUt,vx9xM无返回值r2lyg。56r6L5   接下来就是有参数ZqX7r6QZ8iokvr,528ysPVxvKu有返回值这种较为复杂的情况H1K0U8xH3SxQA。UEH4KYK57Jw 1 package com.coderbuff.custom;1z22975C682 quO5Xn2 pERAcuNyq 7cqnD063 /**m00fP5LzaC 9r4I52iR19C4 * 函数接口97d1K32iL20Y:7n2QNqeSTL只有一个方法的接口QBag4pfzM6。4QBmc2qSS5lNMW作为Lambda表达式的类型lWC07v2jptnHE bUmn0Gw805 * Created by Kevin on 2018/2/17.4IGJ6QuE7 XgpxY47qYdt6 */3V3K8QTD15 0z6a51m9m7 public interface FunctionInterface {RD6aTEE83Ze7 nx2m3c28 boolean test(T param);Jvb613ecv 0jPt9H33bBce9 }   测试Ap2FScw:aSp1O57oY 1 package com.coderbuff.custom;5osiA6ea5 fqYgIsDZDCa6 2 92uF7URBm RI3q0M3jfg 3 import org.junit.Test;2C1fTz4wA5lL1 fgN642 4 46WGIDJ v4kKebFx 5 /**B0dC34k6ImA26 5u84F0kro1II4r 6 * 函数接口测试9I22dZr8 PMXjW39s7k 7 * Created by Kevin on 2018/2/17.PFyYautz375 fCnUq0K4h 8 */47dgi2j6Z86j3 k4WpX3fx9n2H 9 public class FunctionInterfaceTest {3056leHce8Ud5 2d2rTt4n10 UecI2simUbtaoU A8ucE1XceQ611    @TestAYdR369Z7 8RblL5lw6C6X5q12 public void testLambda() {QyZ5008y4K7Rx uu4o1P6D813 //使用Lambda表达式代替匿名内部类LTnw5mih0HAW1S 8M1rh14 func((Integer x) -> true);1B3ZnV2 A9fEK15    }Vjnv6R 71dJoibMfC0s16 lqYFa8CFR3 3J3gcbQ73oy17 private void func(FunctionInterface functionInterface) {6v95sd n16QuzF18 int x = 1;QfCNg m46w4fUmF10Ye19        functionInterface.test(x);NT76R wa9jY80S320    }57t2Hu6D0ErI1 56XtBQUA5D21 }   此时的Lambda表达式“(Integer x) -> true”Q2s405,LjbZD0右边是表达式的主体r7jR5XpV7IoT3A,X3E941VVO5v直接返回true8fdzZXR5,1y38V2g4hG如果有多行代码amJ9jXP6,9C1uBBziAx则可以直接使用花括号表示9l3z59TWp677E3,vrY185a例如qkI31U3wY:D7UzG7U func((Integer x) -> {gnhO1Dlz2 MSS8VMYGd    System.out.println("Hello World" + x);27LcmzW3 0avBFF    return true;dgj40yqB54SLz7 jeoOVES9L11WbM});   Lambda表达式基本的语法规则SE35hDqCz7:2A34FQZ3NX   无参数nfs5NkX922Vm,Bag7Fi无返回值UIIVnUde0yGY;fVq9Mvr39   有参数i2bBpL50192B,GWLHa10nqy4无返回值Ko3W9I3L6;9DB83jA7xV   有参数aB3DcNi1OZ9Hg,ghevg有返回值kpuT61babmK8br。51A4q23p   这三种基本情况已经大致清楚了rbP01,bJ6Zce7Z7特别是需要弄清9ay23cjRs,3mK434Ke3omF什么时候可以使用Lambda表达式代替匿名内部类0e21YK,7Uym312YW1i也就是Lambda表达式的应用场景是函数接口LaUB9Z。WfY11VLambda表达式这一新特性在JDK8中的引入oVAZf0E6621Oo8,3z3dgXg更大的好处则是集合API的更新zunSO40Z5p,ex5PTdJlt6新增的Stream类库puX6LH0T,YO1bid0cuDQ使得我们在遍历使用集合时不再像以往那样不断地使用for循环B28QO5。0ia9Lt1pc JDK8使用集合的正确姿势   示例45y9TNjEY3v:IhZQ00txBL计算来自“chengdu”的学生数量有多少MK69Tl1NV1Fd。2759Yz3r   在JDK8前的代码0c5HGZUm:6Gy88 for (Student student : studentList) {4vLJs1rBQO51 U34B6j7    if (student.getCity().equals("chengdu")) {AZX2K93rv uthct5Z        count++;53xlIP BP9Bo20Kj    }qxX4l nKl5bNqS0}   JDK8使用集合的正确姿势GXTWMrbk:4rkOyc2NHb count = studentList.stream().filter((student -> student.getCity().equals("chengdu"))).count();   API的使用“难度”恰似提高了SUf4s,en59gcBqxOH实际只是不熟悉而已iSqn1fBt7h9H。zO87nwcQryLv26传统迭代的方式需要阅读完整个循环才能明白代码逻辑PC3BZ0MSYJ6d5,6oMEKr5JDK8通过流的方式则可以望文生义且代码量大大减小4P5Q50U4od5g。KHGnE   其中最为重要的是——Stream流4Ow1E5h1。n8V398157tad4Stream的是通过函数式编程方式实现的在集合类上进行复杂操作的工具WvP89X338HPN。O9LJG若要详细讲解Stream的实现方式我相信再写一篇博客也不为过dJlA1f7IuVn,Qz9zZJu6所以此处不再考查Stream的内部实现Xq4L66fC0RH。xsU48YfJtb0这里是想告诉大家58zA8J1qyx,aW6s602如果有幸使用JDK8的开发环境进行开发EenL570L2y9,J4YJ35MKBg44t尽量学习使用新的集合操作APIj6L1DMe。0RGmy0f18kue   上面对于Lambda表达式以及函数式编程仅仅只是到了一个“认识”的地步46J34,5LKbu72OIN似乎只是感受到了缩小代码量d5A19AxE1,9I2Hv0DaNG本文对于Lambda式的认识不深入更多的是对于后面更多的知识做一个铺垫或者作为一个扫盲贴nq6Ur1R4SPWa,3i1PLV1Nk有关Lambda表达式的应用太多XAzPg792uuSxYb,Ca96diGN5T7并发编程X8hrhWa1cEP5hd、M3ucpqAwfBAUe响应式编程等等w50xyok。PUg522P1n4F1G如果你有关于Lambda表达式或者函数式编程有更好的见解不妨留下评论3QVFM95gJK。KMiJ73O 这是一个能给程序员加buff的公众号 不积跬步a31a6pc1T5m,0KmDg无以至千里KucU4lmNwR;F8fce不积小流5EQ77rkGG02,61006c5无以成江海