lambda语法

ads

从JDK1.8开始,JAVA引入了Lambda表达式,现在看来应该算得上是老东西了。但是很多时候做代码review还是能发现不少没有必要的无用代码,影响阅读,写的时候也觉得有点麻烦,不简洁。这个时候Lambda的重要性就提现出来了。

先笼统的介绍一下Lambda的好处,毕竟知道了它能为我们带来什么价值,我们才有衡量是否采用的标准。当然这些都是网上随便搜搜都是一大把的。

1.简洁优雅

Lambda表达式使代码更加简洁和易读。它允许开发人员使用更少的代码来表达功能,特别是在处理函数式接口时,可以避免冗余的匿名内部类语法。

2.函数式编程

Lambda表达式使Java更接近函数式编程的范式。它可以使代码更具函数式风格,例如通过将函数作为参数传递、在集合上进行函数式操作等。

3.更好的集合操作

Java中的Streams API与Lambda表达式结合使用,可以更便捷地处理集合数据,进行过滤、映射、归约等操作,使集合处理代码更加清晰和简单。

4.并行处理

Lambda表达式为并行处理提供了更好的支持。通过Streams API结合Lambda表达式,可以更容易地编写并行处理的代码,从而充分利用多核处理器的优势。

千篇一律的优点介绍完了,其实缺点才是我重点想说的,因为程序员的底线是不能有bug,再低一些的底线是出了bug可以很容易的找到,从某些方面来讲,lambda在排查一些问题是确实会带来不方便。
1.学习曲线

对于习惯传统Java开发风格的开发人员,学习和理解Lambda表达式可能需要一定时间。特别是对于初学者来说,理解Lambda表达式的概念和语法可能会有些困难。

2.可读性问题

在某些情况下,Lambda表达式可能会导致代码可读性下降,尤其是在一些复杂的Lambda表达式中。如果过度使用Lambda表达式,可能会让代码变得晦涩难懂。

3.调试困难

使用Lambda表达式时,调试代码可能会比传统的方法略微困难一些。Lambda表达式是匿名的,因此在调试时可能不太容易追踪到具体的代码。 好了,优点缺点都说完了,我们可以有选择的在某些场景来使用lambda来让我们的代码更简洁高效一些。

下边开始举例应用场景和示例代码,本文中的每个例子都是可以直接复制到开发工具中执行的。

一、遍历

很基础的功能,代码中有注释,一眼懂。
  1. public class IteratorExample {

  2. public static void main(String[] args) {

  3. // 先定义一个List, 注意此方法声明的列表不可变,不能进行添加或删除操作

  4. List<Integer> numList = Arrays.asList(213,34,1,213);

  5. // 不用lambda方式的遍历

  6. for (Integer integer : numList) {

  7. System.out.println(integer);

  8. }

  9. // 用lambda方式的遍历

  10. numList.forEach(System.out::println);

  11. // lambda完整调用代码。 o代表numList中的一个元素 -> {} 是lambda的标准用法

  12. numList.forEach(o -> {

  13. System.out.println(o);

  14. });

  15. // 当lambda调用的方法参数和传参一致时,就可以用上方一行的简易写法

  16. }

  17. }

二、过滤

例子中声明了一个UserInfo对象,填充了一些值,我们要做得是把姓王的用户都过滤出来。这是一个很典型的数据批处理场景,传统写法for循环处理用了6行,但是用Lambda的方式只用了一行就搞定。
这种场景就是没有复杂业务,用for循环不会写错,用lambda就一定也不会写错。
  1. public class FilterExample {

  2. static class UserInfo{

  3. private String name;

  4. public UserInfo(String name){

  5. this.name = name;

  6. }

  7. public String getName() {

  8. return name;

  9. }

  10. public void setName(String name) {

  11. this.name = name;

  12. }

  13. }

  14. public static void main(String[] args) {

  15. UserInfo a = new UserInfo("张三");

  16. UserInfo b = new UserInfo("李四");

  17. UserInfo c = new UserInfo("王五");

  18. UserInfo d = new UserInfo("王六");

  19. List<UserInfo> list = Arrays.asList(a,b,c,d);

  20. // 需求: 过滤出姓王的用户

  21. // 传统写法

  22. List<UserInfo> result1 = new ArrayList<>();

  23. for (UserInfo userInfo : list) {

  24. if (userInfo.getName().startsWith("王")){

  25. result1.add(userInfo);

  26. }

  27. }

  28. result1.forEach(o-> System.out.println(o.getName()));

  29. // 使用lambda写法

  30. List<UserInfo> result2 = list.stream().filter(o->o.getName().startsWith("王")).collect(Collectors.toList());

  31. result2.forEach(o-> System.out.println(o.getName()));

  32. // 使用lambda过滤大于5的数字

  33. List<Integer> numList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

  34. List<Integer> result3 = numList.stream().filter(item-> item>5).collect(Collectors.toList());

  35. result3.forEach(o-> System.out.println(o));

  36. }

  37. }

三、排序

很常见的业务场景,比如需要拉出一个订单列表,按某个字段值来进行排序。使用传统的Collections.sort会自动实现接口中的compare方法,一下子就多出来一坨代码,其中大部分对我们来说都是无用代码。传统的实现方式如果不会写错,那用Lambda就更不会出错了,只需一行代码就可以完成排序。顺带提一嘴o1.compare(o2)是升序,调换位置就是降序。
  1. public class SortExample {

  2. public static void main(String[] args) {

  3. // 先定义一个List, 注意此方法声明的列表不可变,不能进行添加或删除操作

  4. List<Integer> numList = Arrays.asList(213,34,1,213);

  5. // 不用lambda方式的排序

  6. Collections.sort(numList, new Comparator<Integer>() {

  7. @Override

  8. public int compare(Integer o1, Integer o2) {

  9. return o1.compareTo(o2);

  10. }

  11. });

  12. System.out.println(numList);

  13. // 使用lambda方式的排序,为了看到排序变化,这里改成倒序

  14. Collections.sort(numList, (o1, o2) -> o2.compareTo(o1));

  15. System.out.println(numList);

  16. }

  17. }

四、映射

名字不知道对不对,其实是不知道如何概括这个操作,与其说是映射,不如说是从数据管道中拿到自己想要的数据。例子中同样使用List来做操作,通过Lambda的方式拿到想要的字段集合。一行代码代替了6行代码,而且可读性不错。
  1. public class MapExample {

  2. static class UserInfo{

  3. private String name;

  4. public UserInfo(String name){

  5. this.name = name;

  6. }

  7. public String getName() {

  8. return name;

  9. }

  10. public void setName(String name) {

  11. this.name = name;

  12. }

  13. }

  14. public static void main(String[] args) {

  15. UserInfo a = new UserInfo("张三");

  16. UserInfo b = new UserInfo("李四");

  17. UserInfo c = new UserInfo("王五");

  18. UserInfo d = new UserInfo("王六");

  19. List<UserInfo> list = Arrays.asList(a,b,c,d);

  20. // 需求: 取出list中用户信息的名称

  21. // 传统写法

  22. List<String> nameList = new ArrayList<>();

  23. for (UserInfo userInfo : list) {

  24. nameList.add(userInfo.getName());

  25. }

  26. nameList.forEach(System.out::println);

  27. // lambda写法

  28. // List<?>需要定义什么类型, map(对象::属性)就返回对应的类型值

  29. List<String> nameList2 = list.stream().map(UserInfo::getName).collect(Collectors.toList());

  30. nameList2.forEach(System.out::println);

  31. }

  32. }

五、分组

就我个人而言,这个用法是我在Lambda表达式中体验最好的一个。把一个大列表按照不同的规则拆分成几个列表存起来。
该操作的效率是相对较高的,其时间复杂度通常是 O(n),如果数据量很大,那么操作的效率可能会受到影响。其次这个分组条件非常复杂或计算量较大,那么操作的效率可能会相应降低。但是通常情况下,分类条件都是简单的字段或方法引用,所以效率通常不会受到太大的影响。
冗余的一大坨代码和言简意赅的一行代码,相信你会做出自己的选择。
  1. public class GroupExample {

  2. static class UserInfo{

  3. private String name;

  4. private Integer gender;

  5. public UserInfo(String name, Integer gender) {

  6. this.name = name;

  7. this.gender = gender;

  8. }

  9. public Integer getGender() {

  10. return gender;

  11. }

  12. public void setGender(Integer gender) {

  13. this.gender = gender;

  14. }

  15. public String getName() {

  16. return name;

  17. }

  18. public void setName(String name) {

  19. this.name = name;

  20. }

  21. }

  22. public static void main(String[] args) {

  23. UserInfo a = new UserInfo("张三",1);

  24. UserInfo b = new UserInfo("李四",2);

  25. UserInfo c = new UserInfo("王五",1);

  26. UserInfo d = new UserInfo("王六",0);

  27. List<UserInfo> list = Arrays.asList(a,b,c,d);

  28. // 需求: 按性别分组存入不同的集合

  29. // 传统写法

  30. Map<Integer,List<UserInfo>> result1 = new HashMap<>();

  31. for (UserInfo userInfo : list) {

  32. Integer key = userInfo.getGender();

  33. if (!result1.containsKey(key)){

  34. result1.put(key,new ArrayList<>());

  35. }

  36. result1.get(key).add(userInfo);

  37. }

  38. result1.forEach((k,v)->{

  39. System.out.println("group:" +k);

  40. v.forEach(GroupExample::printUserName);

  41. });

  42. // lambda写法

  43. Map<Integer,List<UserInfo>> result2 = list.stream().collect(Collectors.groupingBy((UserInfo::getGender)));

  44. result2.forEach((k,v)->{

  45. System.out.println("group:" +k);

  46. v.forEach(GroupExample::printUserName);

  47. });

  48. }

  49. // 定义一个静态方法用于打印UserInfo对象信息

  50. public static void printUserName(UserInfo userInfo) {

  51. System.out.println(userInfo.getName());

  52. }

  53. }

六、聚合

Lambda中的聚合操作适用于对集合中的元素进行汇总、归约或合并的场景。这些操作通常将集合中的多个元素合并为一个单一的结果。Java中的Stream API提供了丰富的聚合操作,可以方便地处理集合数据。这个例子中只举例了归约和.sum求和三种不同写法。其余的操作还有计算总数(.count)、求平均值(.average)、求最大/最小值(.max/.min)、拼接字符串等,还支持一些更复杂的操作。想研究的话网上搜索“lambda聚合操作”可以慢慢研究。
  1. public class ReduceExample {

  2. public static void main(String[] args) {

  3. List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

  4. // 需求:求list中所有元素的和

  5. // 传统写法

  6. int sum = 0;

  7. for (Integer integer : list) {

  8. sum += integer;

  9. }

  10. System.out.println(sum);

  11. // lambda写法1

  12. Integer integer = list.stream().reduce(0, Integer::sum);

  13. System.out.println(integer);

  14. // lambda写法2 第一个参数为初始值, 后边的参数是每次循环计算得出的结果和下一个元素

  15. Integer integer2 = list.stream().reduce(0, (currentElement, nextElement) -> currentElement + nextElement);

  16. System.out.println(integer2);

  17. // lambda写法3 .sum()求和

  18. Integer integer3 = list.stream().mapToInt(Integer::intValue).sum();

  19. System.out.println(integer3);

  20. }

  21. }

七、函数式接口

需要特别注意的是函数式接口必须只包含一个抽象方法。如果接口中包含多个抽象方法,将无法使用Lambda表达式来实现该接口。个人大部分使用函数式接口的时候是使用jdk或者其他类库的方法时使用,比如示例代码中的创建线程。
  1. interface CustomInterface{

  2. public Integer sum(Integer a, Integer b);

  3. }

  4. public class FunctionInterfaceExample {

  5. public static void main(String[] args) {

  6. // 传统调用接口方法

  7. CustomInterface customInterface = new CustomInterface() {

  8. @Override

  9. public Integer sum(Integer a, Integer b) {

  10. return a + b;

  11. }

  12. };

  13. Integer result = customInterface.sum(1,2);

  14. System.out.println(result);

  15. //lambda调用接口方法

  16. //lambda表达式适用于只有一个抽象方法的接口,被称为函数式接口

  17. CustomInterface custom1 = (a, b) -> a + b;

  18. Integer result1 = custom1.sum(1,2);

  19. System.out.println(result1);

  20. // ===实用比如创建线程===

  21. // 传统写法

  22. Thread thread1 = new Thread(){

  23. @Override

  24. public void run() {

  25. System.out.println(Thread.currentThread().getName());

  26. }

  27. };

  28. thread1.start();

  29. // lambda写法

  30. Thread thread2 = new Thread(() -> System.out.println(Thread.currentThread().getName()));

  31. thread2.start();

  32. }

  33. }

这是我第一篇文章,不管写的好与坏对我个人来讲算是个正面影响吧。逼着自己去总结归纳一些偏模板和工具化的内容,这是很多人嗤之以鼻的事情,毕竟CTRL+C、CTRL+V时间久了会降低个人的编码能力,但是好记性不如烂笔头,每个人都有自认为有意义的事情去做,这也是为什么名字会起“拾荒”这个名字。加油吧


最后编辑于:2024/1/7 拔丝英语网

admin-avatar

英语作文代写、国外视频下载

高质量学习资料分享

admin@buzzrecipe.com