Java 8 新特性之Lambda表达式和Stream流 红太狼 2022-12-03 12:58 209阅读 0赞 ## 1. 为什么需要函数式编程 ## 在很长的一段时间里,Java一直是面向对象的语言,一切皆对象,如果想要调用一个函数,函数必须属于一个类或对象,然后在使用类或对象进行调用。但是在其它的编程语言中,如js,c++,我们可以直接写一个函数,然后在需要的时候进行调用,即可以说是面向对象编程,也可以说是函数式编程。 从功能上来看,面向对象编程没什么不好的地方,但是从开发的角度来看,面向对象编程会多写很多可能是重复的代码行。比如创建一个Runnable的匿名类的时候: Runnable runnable = new Runnable() { @Override public void run() { System.out.println("do something..."); } }; 使用函数式编程之后: // 一行即可 Runnable runnable = () -> System.out.println("do something..."); ## 2.Lambda表达式: ## Lambda表达式取代了匿名类,取消了模板,允许用函数式风格编写代码。这样的优势是:可读性更好,表达更清晰。 在Java生态系统中,函数式表达与对面向对象的全面支持是个激动人心的进步。将进一步促进并行第三方库的发展,充分利用多核CPU。 在Java 8里面,**所有的Lambda的类型都是一个接口,而Lambda表达式本身,也就是”那段代码“,需要是这个接口的实现。**这是理解Lambda的一个关键所在,简而言之就是,**Lambda表达式本身就是一个接口的实现**。 // 无参数, 返回1+2的结果 () -> 1+2; // 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x; // 接收2个参数(数字),返回表达式运算的结果 (x, y) -> x + y; // 多个语句要用大括号包裹, 并且返回值要用return指明 (x, y) -> { int result = x + y; System.out.print(result); return result; }; Lambda表达式有如下约定: > * 一个 Lambda 表达式可以有零个或多个参数; > * 参数的类型既可以明确声明,也可以根据上下文来推断。例如:`(int a)`与`(a)`效果相同; > * 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:`(a, b)` 或 `(int a, int b)` 或 `(String a, int b, float c);` > * 空圆括号代表参数集为空。例如:`() -> 42;` > * 当只有一个参数,且其类型可推导时,圆括号()可省略。例如:`a -> return a*a;` > * Lambda 表达式的主体可包含零条或多条语句; > * 如果 Lambda 表达式的主体只有一条语句,花括号\{\}可省略。匿名函数的返回类型与该主体表达式一致; > * 如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号\{\}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空。 ### 1. 无参数的Lambda表达式 ### **1) 如果只有一行的时候,不需要加 分号;** Thread类的使用 public class Main { public static void main(String[] args) { new Thread( () -> System.out.println("this is thread") ).start(); } } Runnable接口的使用,调用的是run() 方法 public class Main { public static void main(String[] args) { Runnable myrun = () -> System.out.println("this is test"); myrun.run(); } } **2) 如果是多行输出的话,则需要 中括号 括起来 \{ \},并且需要加 分号** public class Main { public static void main(String[] args) { new Thread( () -> { System.out.println("this is thread"); System.out.println("this is sencond"); } ).start(); } } ### 2. 带参数的Lambda表达式 ### import java.util.Arrays; import java.util.Collections; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = Arrays.asList("kk", "yi", "name", "opk"); Collections.sort(list, (s1, s2) -> { // 此处s1,s2可以不用自定义类型 if (s1 == null){ return -1; } if (s2 == null){ return 1; } return s1.length() - s2.length(); } ); list.forEach(System.out::println); // Lambda表达式,打印list;不用使用For循环 } } 除了省略了接口名和方法名,代码中把参数表的类型也省略了。这得益于`javac`的**类型推断**机制,编译器能够根据上下文信息推断出参数的类型,当然也有推断失败的时候,这时就需要手动指明参数类型了。注意,Java是强类型语言,每个变量和对象都必需有明确的类型。 在 Java 8 中使用双冒号操作符(double colon operator),代表使用方法 也可以使用下列的方法: // 使用 lambda 表达式以及函数操作(functional operation) list.forEach((list) -> System.out.print(list+ "; ")); 在图形用户界面程序中,匿名类可以使用lambda表达式来代替 // 使用匿名内部类 btn.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("Hello World!"); } }); // 或者使用 lambda expression btn.setOnAction(event -> System.out.println("Hello World!")); **1)removeIf() 方法** **删除满足于表达式的条件** import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<String> list = new ArrayList(Arrays.asList("kk", "yi", "name", "opk")); list.removeIf(str -> str.length() < 3); list.forEach(System.out::println); } } **2)replaceAll() 方法** *假设有一个字符串列表,将其中所有长度大于3的元素转换成大写,其余元素不变。* import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<String> list = new ArrayList(Arrays.asList("kk", "yi", "name", "opk")); list.replaceAll(str -> { if (str.length() >2){ // 将字符串长度大于2的,转换成大写字母 return str.toUpperCase(); } return str; }); list.forEach(System.out::println); } } **3)sort() 方法** *假设有一个字符串列表,按照字符串长度增序对元素排序。长度越长的,排在越后面* import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<String> list = new ArrayList(Arrays.asList("kk", "yiyyy", "name", "opk")); list.sort((str1, str2) -> str1.length() - str2.length() ); list.forEach(System.out::println); } } ## 3.Stream流处理: ## Stream是对集合的包装,通常和lambda一起使用。 使用lambdas可以支持许多操作,如 map, filter, limit, sorted, count, min, max, sum, collect 等等。 同样,Stream使用**懒运算**,他们并不会真正地读取所有数据,遇到像collect() 这样的方法就会结束链式语法 1. **代码简洁**函数式编程写出的代码简洁且意图明确,使用*stream*接口让你从此告别*for*循环。 2. **多核友好**,Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下`parallel()`方法。 得到一个*stream*通常不会手动创建,而是调用对应的工具方法,比如: * 调用`Collection.stream()`或者`Collection.parallelStream()`方法 * 调用`Arrays.stream(T[] array)`方法 虽然大部分情况下*stream*是容器调用`Collection.stream()`方法得到的,但*stream*和*collections*有以下不同: * **无存储**。*stream*不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。 * **为函数式编程而生**。对*stream*的任何修改都不会修改背后的数据源,比如对*stream*执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新*stream*。 * **惰式执行**。*stream*上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。 * **可消费性**。*stream*只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。 这类似于 Spark 的RRD数据操作形式 下表汇总了`Stream`接口的部分常见方法: <table> <thead> <tr> <th>操作类型</th> <th>接口方法</th> </tr> </thead> <tbody> <tr> <td>中间操作</td> <td>concat() distinct() filter() flatMap() limit() map() peek()<br> skip() sorted() parallel() sequential() unordered()</td> </tr> <tr> <td>结束操作</td> <td>allMatch() anyMatch() collect() count() findAny() findFirst()<br> forEach() forEachOrdered() max() min() noneMatch() reduce() toArray()</td> </tr> </tbody> </table> ### `1)map` 操作就可以使用该函数,将一个流中的值转换成一个新的流。 ### 将数组的每项增加 10 import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6)); list.stream() .map(m -> m + 10) // 将每项增加10 .forEach(m -> System.out.println(m)); // 打印出数组 } ![format_png][] ### **`2)Stream` 中提供的新方法 `filter`** ### **`用于`判断对象是否符合条件,符合条件的才保留下来** 将 满足 filter 方法条件的数组保存下来 import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6)); list.stream() .filter(m -> m > 4) .forEach(m -> System.out.println(m)); // 打印出数组 5,6 } } ![format_png 1][] ### 3)`flatMap` 方法可用 `Stream` 替换值,然后将多个 `Stream` 连接成一个 `Stream` ### import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; import java.util.Comparator; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> teamIndia = Arrays.asList("Virat", "Dhoni", "Jadeja"); List<String> teamAustralia = Arrays.asList("Warner", "Watson", "Smith"); List<String> teamEngland = Arrays.asList("Alex", "Bell", "Broad"); List<String> teamNewZeland = Arrays.asList("Kane", "Nathan", "Vettori"); List<String> teamSouthAfrica = Arrays.asList("AB", "Amla", "Faf"); List<String> teamWestIndies = Arrays.asList("Sammy", "Gayle", "Narine"); List<String> teamSriLanka = Arrays.asList("Mahela", "Sanga", "Dilshan"); List<String> teamPakistan = Arrays.asList("Misbah", "Afridi", "Shehzad"); List<List<String>> playersInWorldCup2016 = new ArrayList<>(); playersInWorldCup2016.add(teamIndia); playersInWorldCup2016.add(teamAustralia); playersInWorldCup2016.add(teamEngland); playersInWorldCup2016.add(teamNewZeland); playersInWorldCup2016.add(teamSouthAfrica); playersInWorldCup2016.add(teamWestIndies); playersInWorldCup2016.add(teamSriLanka); playersInWorldCup2016.add(teamPakistan); List<String> list = playersInWorldCup2016.stream() .flatMap(pList -> pList.stream()) .collect(Collectors.toList()); System.out.println(list); } } 输出结果:[Virat, Dhoni, Jadeja, Warner, Watson, Smith, Alex, Bell, Broad, Kane, Nathan, Vettori, AB, Amla, Faf, Sammy, Gayle, Narine, Mahela, Sanga, Dilshan, Misbah, Afridi, Shehzad] ![format_png 2][] ### 4)`Stream` 上常用的操作之一是求最大值和最小值。 ### Stream API 中的 `max` 和 `min` 操作足以解决这一问题 获取最大值最小值 `min`可以对整型流求最小值,返回`OptionalInt`。 `max`可以对整型流求最大值,返回`OptionalInt`。 这两个方法是结束操作,只能调用一次。 min 和 max 函数需要一个 Comparator 对象为参数作为比对依据。 找到数组中最小的数字 import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6)); System.out.println(list.stream().min(Comparator.comparing(Integer::valueOf)).get()); } } ### 5)`reduce` 操作可以实现从一组值中生成一个值 ### ![format_png 3][] import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6)); int k = list.stream(). reduce((n1, n2) -> n1 + n2) .get(); System.out.println(k); } } 或者: import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6)); int k = list.stream(). reduce(0, (n1, n2) -> n1 + n2); System.out.println(k); } } ### 5)数据并行化处理 ### 数据并行化是指将数据分成块,为每块数据分配单独的处理单元。这样可以充分利用多核 CPU 的优势。 使用 parallelStream() ![format_png 4][] import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6)); list.parallelStream() .forEach(System.out::println); } } 得到的数据不是按顺序的 1,2,3,4,5,6, 而是乱序的数字 ### 6)limt(), skip(), distinct(), ### limit() 方法,和数据库的limit 方法一样,取指定的前 n 项数字 import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5, 6)); list.stream() .limit(3) // 只打印前3 个数数字 .forEach(m -> System.out.println(m)); // 打印出数组 1,2,3 } } `skip() 方法:`用于排除前多少个结果。 distinct() 方法,用于剔除重复,与数据库中的`distinct`用法一致。 \--------------------------- end --------------------------- ### 项目推荐: ### **[2000多G的计算机各行业电子资源分享(持续更新)][2000_G]** **[2020年微信小程序全栈项目之喵喵交友【附课件和源码】][2020]** **[Spring Boot开发小而美的个人博客【附课件和源码】][Spring Boot]** **[Java微服务实战296集大型视频-谷粒商城【附代码和课件】][Java_296_-]** **[Java开发微服务畅购商城实战【全357集大项目】-附代码和课件][Java_357_-]** **[最全最详细数据结构与算法视频-【附课件和源码】][-]** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNTg3NTc1_size_16_color_FFFFFF_t_70_pic_center] \----------------------------------------------------------------------------- [format_png]: /images/20221123/80fc29b3d0fe44fa97fde76bbbcd365f.png [format_png 1]: /images/20221123/75d24f51dfb04e299b0bc5628503f2bf.png [format_png 2]: /images/20221123/d044358489604a208d0cb27d86db4513.png [format_png 3]: /images/20221123/19fdd64cbdd94de49c264a930f1d261a.png [format_png 4]: /images/20221123/e8b652e32ebb494b826b3ffc057535db.png [2000_G]: https://mp.weixin.qq.com/s/sP4JgGWkCzpgwKr9sAV2_Q [2020]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247487704&idx=1&sn=5f4b2127c4d49fd07ae072a0721424a2&chksm=e8036fc2df74e6d489c4aa9b06f917ef7cee6027f13e150fca53cf79d5d188d4ccc1af49e098&scene=21#wechat_redirect [Spring Boot]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247487798&idx=2&sn=ac0293b996521b872a9dba5fbb3e65e6&chksm=e8036e2cdf74e73aba104a9a994a5b2e31483e8dcbe0f1d9936f6d5173b887e1560f59d2819c&scene=21#wechat_redirect [Java_296_-]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247487674&idx=1&sn=7aff0bdf2bb727303f3d3618995aef21&chksm=e8036fa0df74e6b6d872c7e6ece179c524ed463a4a6b74c96875475c9a3d5ddb903427dd993b&scene=21#wechat_redirect [Java_357_-]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247486376&idx=1&sn=d1fef270c463ea8ac663f6fbfedd70a0&chksm=e80374b2df74fda4d3bafba878a106a19e18c5fcda266008f4f37975847a21bc612ffcd5ff39&scene=21#wechat_redirect [-]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247487750&idx=1&sn=747bccbb5f5ea6b58915198de40da777&chksm=e8036e1cdf74e70ae97a5e8e265b49d7236d904d291203309159d07ba1724033062c0e370843&scene=21#wechat_redirect [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNTg3NTc1_size_16_color_FFFFFF_t_70_pic_center]: /images/20221123/ff10debb0c5340e9b67a39bed9a90dca.png
还没有评论,来说两句吧...