感受 lambda 之美!上

简介: 感受 lambda 之美!上




一、引言

java8最大的特性就是引入Lambda表达式,即函数式编程,可以将行为进行传递。总结就是:使用不可变值与函数,函数对不可变值进行处理,映射成另一个值。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

二、java重要的函数式接口

1、什么是函数式接口

函数接口是只有一个抽象方法的接口,用作 Lambda 表达式的类型。使用@FunctionalInterface注解修饰的类,编译器会检测该类是否只有一个抽象方法或接口,否则,会报错。可以有多个默认方法,静态方法。

1.1 java8自带的常用函数式接口。

函数接口 抽象方法 功能 参数 返回类型 示例
Predicate test(T t) 判断真假 T boolean 9龙的身高大于185cm吗?
Consumer accept(T t) 消费消息 T void 输出一个值
Function R apply(T t) 将T映射为R(转换功能) T R 获得student对象的名字
Supplier T get() 生产消息 None T 工厂方法
UnaryOperator T apply(T t) 一元操作 T T 逻辑非(!)
BinaryOperator apply(T t, U u) 二元操作 (T,T) (T) 求两个数的乘积(*)
public class Test {
    public static void main(String[] args) {
        Predicate<Integer> predicate = x -> x > 185;
        Student student = new Student("9龙", 23, 175);
        System.out.println(
            "9龙的身高高于185吗?:" + predicate.test(student.getStature()));
        Consumer<String> consumer = System.out::println;
        consumer.accept("命运由我不由天");
        Function<Student, String> function = Student::getName;
        String name = function.apply(student);
        System.out.println(name);
        Supplier<Integer> supplier =
            () -> Integer.valueOf(BigDecimal.TEN.toString());
        System.out.println(supplier.get());
        UnaryOperator<Boolean> unaryOperator = uglily -> !uglily;
        Boolean apply2 = unaryOperator.apply(true);
        System.out.println(apply2);
        BinaryOperator<Integer> operator = (x, y) -> x * y;
        Integer integer = operator.apply(2, 3);
        System.out.println(integer);
        test(() -> "我是一个演示的函数式接口");
    }
    /**
     * 演示自定义函数式接口使用
     *
     * @param worker
     */
    public static void test(Worker worker) {
        String work = worker.work();
        System.out.println(work);
    }
    public interface Worker {
        String work();
    }
}
//9龙的身高高于185吗?:false
//命运由我不由天
//9龙
//10
//false
//6
//我是一个演示的函数式接口

以上演示了lambda接口的使用及自定义一个函数式接口并使用。下面,我们看看java8将函数式接口封装到流中如何高效的帮助我们处理集合。

注意:Student::getName 例子中这种编写lambda表达式的方式称为方法引用。 格式为ClassNmae::methodName 。是不是很神奇,java8就是这么迷人。

示例:本篇所有示例都基于以下三个类。OutstandingClass:班级;Student:学生;SpecialityEnum:特长。

1.2 惰性求值与及早求值

惰性求值:只描述Stream,操作的结果也是Stream,这样的操作称为惰性求值。 惰性求值可以像建造者模式一样链式使用,最后再使用及早求值得到最终结果。

及早求值:得到最终的结果而不是Stream,这样的操作称为及早求值。

2、常用的流

2.1 collect(Collectors.toList())

将流转换为list。还有toSet(),toMap()等。及早求值

public class TestCase {
    public static void main(String[] args) {
        List<Student> studentList = Stream.of(new Student("路飞", 22, 175),
                new Student("红发", 40, 180),
                new Student("白胡子", 50, 185)).collect(Collectors.toList());
        System.out.println(studentList);
    }
}
//输出结果
//[Student{name='路飞', age=22, stature=175, specialities=null},
//Student{name='红发', age=40, stature=180, specialities=null},
//Student{name='白胡子', age=50, stature=185, specialities=null}]

2.2 filter

顾名思义,起过滤筛选 的作用。内部就是Predicate接口。惰性求值。

比如我们筛选出出身高小于180的同学。

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));
        List<Student> list = students.stream()
            .filter(stu -> stu.getStature() < 180)
            .collect(Collectors.toList());
        System.out.println(list);
    }
}
//输出结果
//[Student{name='路飞', age=22, stature=175, specialities=null}]

2.3 map

转换功能,内部就是Function接口。惰性求值

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));
        List<String> names = students.stream().map(student -> student.getName())
                .collect(Collectors.toList());
        System.out.println(names);
    }
}
//输出结果
//[路飞, 红发, 白胡子]

例子中将student对象转换为String对象,获取student的名字。

2.4 flatMap

将多个Stream合并为一个Stream。惰性求值

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));
        List<Student> studentList = Stream.of(students,
                asList(new Student("艾斯", 25, 183),
                        new Student("雷利", 48, 176)))
                .flatMap(students1 -> students1.stream()).collect(Collectors.toList());
        System.out.println(studentList);
    }
}
//输出结果
//[Student{name='路飞', age=22, stature=175, specialities=null},
//Student{name='红发', age=40, stature=180, specialities=null},
//Student{name='白胡子', age=50, stature=185, specialities=null},
//Student{name='艾斯', age=25, stature=183, specialities=null},
//Student{name='雷利', age=48, stature=176, specialities=null}]

调用Stream.of的静态方法将两个list转换为Stream,再通过flatMap将两个流合并为一个。

2.5 max和min

我们经常会在集合中求最大或最小值 ,使用流就很方便。及早求值。

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));
        Optional<Student> max = students.stream()
            .max(Comparator.comparing(stu -> stu.getAge()));
        Optional<Student> min = students.stream()
            .min(Comparator.comparing(stu -> stu.getAge()));
        //判断是否有值
        if (max.isPresent()) {
            System.out.println(max.get());
        }
        if (min.isPresent()) {
            System.out.println(min.get());
        }
    }
}
//输出结果
//Student{name='白胡子', age=50, stature=185, specialities=null}
//Student{name='路飞', age=22, stature=175, specialities=null}

max、min接收一个Comparator (例子中使用java8自带的静态函数,只需要传进需要比较值即可。)并且返回一个Optional对象,该对象是java8新增的类,专门为了防止null引发的空指针异常。可以使用max.isPresent()判断是否有值;可以使用max.orElse(new Student()),当值为null时就使用给定值;也可以使用max.orElseGet(() -> new Student());这需要传入一个Supplier的lambda表达式。

相关文章
|
14天前
|
算法 程序员 开发工具
代码之禅:技术感悟与编程实践的融合
【4月更文挑战第27天】 在数字世界的纷繁背后,每一行代码都承载着逻辑与创造的力量。本文以个人编程实践出发,探讨技术发展与个人成长之间的微妙联系。文章不仅记录了作者在技术探索过程中的心得体会,还分享了如何将抽象的编程概念与具体的应用场景相结合,提升开发效率和项目质量。从初学者的困惑到熟练者的自信,再到高手的从容,每个阶段都有其独特的挑战与收获。通过反思与总结,旨在为同行提供一种思维上的启发和技术上的参考。
|
2月前
|
SQL Java 编译器
感受 lambda
感受 lambda
8 0
|
1月前
|
设计模式 算法 开发者
代码之美:探索编程艺术与实践的交汇点
【4月更文挑战第2天】 在数字世界的构建中,代码不仅仅是一种工具,它亦是艺术家手中的画笔。本文旨在探讨编程作为一种技术和艺术相结合的领域,揭示那些隐藏在代码背后的美学原则和创造力。我们将从编程的基础出发,逐步深入到设计模式、算法优雅性以及代码的可读性和维护性,最终探讨如何通过技术实现创新并解决问题。文章的目的是为那些渴望在技术实践中寻找创造性和美感的开发者提供灵感和指导。
|
2月前
|
算法 程序员 开发工具
代码之禅:高效编程的艺术与实践
【2月更文挑战第22天】 在数字时代的浪潮中,编程已不仅仅是一种技术活,它更是一场思维的舞蹈,一种解决问题的艺术。本文将深入探讨如何通过持续学习、精通算法与数据结构、编写可读性强和模块化良好的代码,以及利用版本控制工具来提升编程效率和质量。我们将一起揭开那些隐藏在键盘敲击背后的智慧,探索那些能够使程序员如同艺术家一般在代码世界中自由创作的技巧和方法。
|
4月前
|
算法 程序员 C语言
【高效编程技巧】编程菜鸟和编程大佬的差距究竟在哪里?
【高效编程技巧】编程菜鸟和编程大佬的差距究竟在哪里?
34 0
|
10月前
|
编译器 C++
函数之道:探索C++函数的奥秘
函数之道:探索C++函数的奥秘
|
10月前
|
存储 索引 Python
函数之道:探索python函数的奥秘
函数之道:探索python函数的奥秘
|
消息中间件 SQL JavaScript
感受 lambda 之美!下
感受 lambda 之美!下
|
JavaScript 前端开发 数据库
✨从纯函数讲起,一窥最深刻的函子 Monad
建议按顺序“食用”。饮水知其源,由 lambda 演算演化而来的闭包思想是 JavaScript 写在基因里的东西,闭包的“孪生子”柯里化,是封装高阶函数的利器。
|
容器
爽的上天的lambda,你会用?牛,不妨看看你用过没
最近在业务代码中写了一些没用过的lambda表达式,今天放出来一个例子:看一下我用的那个lambda?
58 0
爽的上天的lambda,你会用?牛,不妨看看你用过没