• Lambda表达式常见用法(提高效率神器)


    Java8中一个非常重要的特性就是Lambda表达式,我们可以把它看成是一种闭包,它允许把函数当做参数来使用,是面向函数式编程的思想,一定程度上可以使代码看起来更加简洁。

    其实以上都不重要,重要的是能够提高我的开发效率,为了工作效率避免无意义加班,使用Lambda表达式只能说好爽!一时用一时爽,一直用一直爽!但是学习可能很多人觉得很复杂于是放弃了,可读性确实很不好,我的建议是死记规则,学习常用的Lambda表达式就够了。因为,其他稀奇古怪的语法很可能被你老大看见了会请你喝茶,所以本篇博客就由浅入深介绍提高工作效率神器——Lambda常用表达式。

    例子切入

    比如创建一个线程并启动,一般我们这样写:

    //匿名内部类写法
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("内部类写法");
        }
    }).start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用Lambda表达式可以这样写:

    new Thread(() -> System.out.println("hello world")).start();
    
    • 1

    我知道你很急,但你先别急,后面我们详细介绍其用法。以上代码表明使用Lambda表达式写起来真的很爽,早写完早下班!如果你司是代码量绩效那别学了,先辞职再说![手动狗头]

    使用场景

    Lambda表达式的最最最常见的使用场景是 接口容器,凡是以后需要实现接口和操作容器都可以考虑使用Lambda表达式。实现接口需要注意,如果接口中仅有一个抽象方法需要实现可以使用Lambda表达式,否则有多个未实现的方法不能使用。上述例子也就是接口使用Lambda表达式的一种实现方式。下面分为接口和容器结合例子进行讲解。

    接口

    首先定义我们自己的接口,就是打印输入的字符串s,如下:

    interface MyPrint{
        public void print(String s);
    }
    
    • 1
    • 2
    • 3

    传统的实现方式就是需要实现MyPrint类然后重写print方法,这里就不再展示,我们直接使用Lambda表达式实现如下:

    MyPrint myPrint = s -> System.out.println(s);
    myPrint.print("hello world 1");
    
    • 1
    • 2

    现在解释上述代码:等号左边是我们的接口类,使用多态的方式父类引用指向子类实现。那么右边就是我们对左边父类的实现。() -> {} 是Lambda的一个语法,()中的字符表示需要传入的参数,不需要写类型,使用占位符即可,如果()中没有参数表示该方法(指的是需要重写的方法)无参。{} 是方法体,具体的实现代码写在 {} 中。如果有多个参数可以写成 (a,b)->{return a+b} ,但是这还不够简介,记住:如果(a)只有一个参数那么不需要写 () 直接写 a,如果 {} 只有一行代码如果有return则不用写 return 也不用写 {},就写出一行需要返回的逻辑实现即可,例如上面代码实现标准写法是:

    MyPrint myPrint = (s) -> {System.out.println(s)};
    
    • 1

    这里,我们再举几个例子说明如下:

    // 1. 不需要参数,返回值为 5  
    () -> 5  
    // 2. 接收一个参数(数字类型),返回其2倍的值  
    x -> 2 * x  
    // 3. 接受2个参数(数字),并返回他们的差值  
    (x, y) -> x – y  
    // 4. 接收2个int型整数,返回他们的和  
    (int x, int y) -> x + y  
    // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
    (String s) -> System.out.print(s)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    总结就是:能偷懒就偷懒,()->{} ,出错那你就按照标准的语法写,反正编译器会告诉你,如果只有一个参数可以省略() ,如果方法体只有一行代码可以省去return 单词和{} 。是不是超级简单,那么下面要升级难度了,
    上述写法还可以进一步写成如下:

    MyPrint myPrint = System.out::println; //等价于 s -> System.out.println(s);
    myPrint.print("hello world 2");
    
    • 1
    • 2

    这里就不得不介绍 :: 号的用法了,我们放到下一节讲解!

    双冒号 :: 的用法

    对于 :: 我的理解如下,假设有个Student类,其中有个方法 getName() ,那么student::getName 的意思就是 传入Student的对象student,调用它的getName()方法。等价于 (Student s)->{s.getName()} , 即

    student::getName   等价于  (s)->{s.getName()} 或者  (Student s)->{s.getName()} 
    
    • 1

    所以,System.out::println 双冒号左边是对象,右边是该对象的方法。那有人会问那么参数s如何传的呢?我们再看,System.out::println; 等价于 s -> System.out.println(s); 其实println需要的是一个字符串参数,而MyPrint的print接口也是一个字符串参数,这种一对一的参数传递其实是隐式传递的,而且如果使用这种写法,参数必须是对应的!

    以上情况是 对象::实例方法名; 那么也可以有 类名::静态方法名,例如 Integer::parseInt ,就是接受一个字符串,解析为整数。等价于 (String s)->{ Integer.parseInt(s)}。你会问你怎么知道参数是String,因为parseInt方法需要的就是String 啊。因此,如果你明白啦以上的规则,其实非常简单!现在还不适应没关系,通过下面的容器集合流处理案例,你会很明白!

    Java 容器集合的Lambda用法

    这里就非常简单了,基本都是Stream流的处理,配合Lambda表达式,简直写起来不要太爽了!这里还是以语法结合案例为驱动来讲解:

    forEach 语法

    使用它替代 for(int a : arr) ,简直太爽了,如下:

     // 使用Lambda表达式替代for循环
     List<Integer> arr = Arrays.asList(4, 1, 25);
     // forEach 表示从容器中依次取出每个元素进行{}中的操作
         arr.forEach(num->{
         int tmp = num+1;
         System.out.println(tmp);
     });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    过滤器 stream().filter()

    对容器中每个对象都进行过滤,如果filter( lambda条件)中的条件判断为true则保留,条件为false则丢弃。案例:提取容器中的奇数数字。

    List<Integer> arr = Arrays.asList(4, 1, 25,3,6);
    List<Integer> o = arr.stream().filter(num -> num % 2 == 1).collect(Collectors.toList());
    System.out.println(o);
    
    • 1
    • 2
    • 3

    .collect(Collectors.toList() 表示重新转为List容器。

    映射器 stream().map()

    对容器中的每个对象都遍历,并对它在 map( lambda操作 ) 中进行一个Lambda表达式的操作,例子:每个数字变成自身的2倍(使用forEach也可以实现):

    List<Integer> arr = Arrays.asList(4, 1, 25,3,6);
    List<Integer> d = arr.stream().map(num -> 2 * num).collect(Collectors.toList());
    System.out.println(d);
    
    • 1
    • 2
    • 3
    groupingBy 分组的使用

    例子:将下面数组按照其字符串长度分组。

    List<String> phones = Arrays.asList("huawei", "xiaomi", "vivo", "iphone","oppo", "laoluo", "oneplus");
    Map<Integer, List<String>> map = phones.stream().collect(Collectors.groupingBy(String::length));
    System.out.println(map);
    
    • 1
    • 2
    • 3
    综合练习题

    最后来一道综合练习题,请先自己做,再看答案!
    将一个字符串数组其中的字符串对应的奇数取出来,再转为整数类型,再排序
    List list = Arrays.asList(“23”, “4”, “11”, “7”, “3”, “8”, “10”);
    应该得到 [3, 7, 11, 23] .

    List<Integer> res = list.stream().map(Integer::parseInt).filter(a -> a % 2 == 1).sorted().collect(Collectors.toList());
    System.out.println(res);
    
    • 1
    • 2

    以上就是 提高工作效率,但不能提高代码效率的常用Lambda表达式。对你有帮助的话帮忙一键三连,点赞-评论-关注!

    假设有如下Student类,我们有关于这个类的集合,那么我们可以有以下操作!

    package strategy.demo.entity;
    public class Student {
        private String name;
        private int age;
        private int score;
        private String address;
    
        public String getName() {
            return name;
        }
        public int getAge() {
            return age;
        }
        public int getScore() {
            return score;
        }
        public String getAddress() {
            return address;
        }
        public void setScore(int score) {
            this.score = score;
        }
        public Student(String name, int age, int score, String address){
            this.name = name;
            this.age = age;
            this.score = score;
            this.address = address;
        }
    
        public String toString(){
            return "Student [name=" + name + ", age=" + age + ", score=" + score + ", address=" + address + "]";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    下面就是对上面的练习:

    package strategy.demo;
    
    import org.junit.Test;
    import strategy.demo.entity.Student;
    import strategy.demo.util.StudentHelps;
    
    import java.util.List;
    import java.util.Map;
    import java.util.OptionalDouble;
    import java.util.stream.Collectors;
    
    public class streamDemo {
    
        /**
         * 中间操作:过滤(filter)、映射(map)、遍历(peek)、扁平化(flatMap)、排序(sorted)、去重(distinct)、截取(limit)、跳过(skip)
         * 终端操作:匹配(anyMatch、allMatch、noneMatch)、查找(findFirst、findAny)、遍历(forEach)
         * 计数(count)、归约(reduce)、收集(collect)、聚合(max、min、sum、average)
         * @param args
         */
        List<Student> allStudents = StudentHelps.getAllStudents();
    
        @Test
        public void filterDemo(){
            // 过滤年龄大于20的学生
            allStudents .stream()
                    // filter 接受一个谓词判断函数,true表示保留,false表示丢弃
                    .filter(student -> student.getAge()>20)
                    .forEach(System.out::println);
        }
    
        @Test
        public void mapDemo(){
            // 映射出所有学生的姓名
            allStudents .stream()
                    // map 接受一个转换函数,将输入的元素转换成另外的元素,这里将Student转换成String
                    .map(student -> student.getName()) // 等价于 .map(Student::getName)
                    .forEach(System.out::println);
    
            // 将每位学生的分数上调10分
            allStudents.stream()
                    .map(student -> {student.setScore(student.getScore()+10); return student;})
                    .forEach(System.out::println);
        }
    
        @Test
        public void peekDemo(){
            // peek 与 forEach 类似,但是不会销毁流,peek之后可以继续操作而forEach之后不能继续操作
            // 与map的操作很类似,但是map是转换操作,而peek是消费操作,两者功能基本上可以互换
            allStudents .stream()
                    .peek(student -> System.out.println(student.getName()))
                    .forEach(System.out::println);
        }
    
        @Test
        public void sortedDemo(){
            // sorted 排序,接受一个Comparator比较器,可以自定义排序规则
            allStudents .stream()
                    .sorted((s1,s2)->s1.getScore()-s2.getScore())
                    .forEach(System.out::println);
        }
        @Test
        public void distinctDemo(){
            // distinct 去重,根据元素的hashCode和equals方法来判断是否重复
            allStudents .stream()
                    .distinct()
                    .forEach(System.out::println);
        }
        @Test
        public void limitDemo(){
            // limit 截取,只保留前n个元素
            allStudents .stream()
                    .sorted((s1,s2)->s2.getScore()-s1.getScore())
                    .limit(3)
                    .forEach(System.out::println);
        }
    
        @Test
        public void skipDemo(){
            // skip 跳过,跳过前n个元素
            allStudents .stream()
                    .sorted((s1,s2)->s2.getScore()-s1.getScore())
                    .skip(3)
                    .forEach(System.out::println);
        }
    
        @Test
        public void anyMatchDemo(){
            // anyMatch 匹配,只要有一个元素满足条件就返回true
            boolean b = allStudents .stream()
                    .anyMatch(student -> student.getScore() > 80);
            System.out.println(b);
        }
    
        @Test
        public void allMatchDemo(){
            // allMatch 匹配,所有元素都满足条件才返回true
            boolean b = allStudents .stream()
                    .allMatch(student -> student.getScore() > 50);
            System.out.println(b);
        }
    
        @Test
        public void noneMatchDemo(){
            // noneMatch 匹配,所有元素都不满足条件才返回true
            boolean b = allStudents .stream()
                    .noneMatch(student -> student.getScore() > 100);
            System.out.println(b);
        }
    
        @Test
        public void findFirstDemo(){
            // findFirst 查找,返回第一个大于80分的学生元素
            Student student = allStudents .stream()
                    .filter(s -> s.getScore() > 80)
                    .findFirst()
                    .get();
            System.out.println(student);
        }
    
        @Test
        public void findAnyDemo(){
            // findAny 查找,返回任意一个大于80分的学生元素
            Student student = allStudents .stream()
                    .filter(s -> s.getScore() > 80)
                    .findAny()
                    .get();
            System.out.println(student);
        }
    
        @Test
        public void countDemo(){
            // count 计数,返回流中大于80分学生元素的个数
            long count = allStudents .stream()
                    .filter(s -> s.getScore() > 80)
                    .count();
            System.out.println(count);
        }
    
        @Test
        public void collectDemo(){
            // collect 收集,将流中的元素收集到一个集合中
            List<Student> students = allStudents .stream()
                    .filter(s -> s.getScore() > 80)
                    .collect(Collectors.toList());
            System.out.println(students);
    
    
            // group 收集,将流中的元素收集到一个集合中
            Map<String, List<Student>> students1 = allStudents .stream()
                    .filter(s -> s.getScore() > 80)
                    .collect(Collectors.groupingBy(Student::getAddress)); // 按照地址进行分组
            System.out.println(students1);
    
            // partition 分区,将流中的元素按照谓词逻辑分为两组
            Map<Boolean, List<Student>> students2 = allStudents .stream()
                    .filter(s -> s.getScore() > 80)
                    .collect(Collectors.partitioningBy(s -> s.getScore() > 90)); // 按照分数是否大于90分进行分区
            System.out.println(students2);
        }
    
        @Test
        public void maxDemo(){
            // max 聚合,返回流中分数最高的学生
            Student student = allStudents .stream()
                    .max((s1, s2) -> s1.getScore() - s2.getScore())
                    .get();
            System.out.println(student);
    
            OptionalDouble maxScore = allStudents.stream()
                    // 将Student转换成double类型的分数
                    .mapToDouble(Student::getScore)
                    .max();
            System.out.println(maxScore.getAsDouble());
        }
    
        @Test
        public void minDemo(){
            // min 聚合,返回流中分数最低的学生
            Student student = allStudents .stream()
                    .min((s1, s2) -> s1.getScore() - s2.getScore())
                    .get();
            System.out.println(student);
    
            OptionalDouble minScore = allStudents.stream()
                    // 将Student转换成double类型的分数
                    .mapToDouble(Student::getScore)
                    .min();
            System.out.println(minScore.getAsDouble());
        }
    
        @Test
        public void sumDemo(){
            // sum 聚合,返回流中所有学生的分数总和
            int sum = allStudents .stream()
                    .mapToInt(Student::getScore)
                    .sum();
            System.out.println(sum);
        }
    
        @Test
        public void averageDemo(){
            // average 聚合,返回流中所有学生的分数平均值
            double average = allStudents .stream()
                    .mapToInt(Student::getScore)
                    .average()
                    .getAsDouble();
            System.out.println(average);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
  • 相关阅读:
    渗透中 POC、EXP、Payload、Shellcode 的区别
    天梯赛 L2-052 吉利矩阵
    C# 静态构造函数未执行 .net core框架
    Java基础实现加油站圈存机系统
    基于STC8H4K64TL单片机的触摸功能调试
    【C++】STL详解(十四)—— bitset(位图)的模拟实现
    操作系统4小时速成:内存管理,程序执行过程,扩充内存,连续分配,非连续分配,虚拟内存,页面替换算法
    Logstash多数据源多输出怎么办?
    在 Linux 上使用 Systemd 运行 Java Jar 应用程序
    454. 四数相加 II
  • 原文地址:https://blog.csdn.net/cj151525/article/details/133383375