每天学一点之Lambda表达式

Lambda表达式

思想导入:

函数式编程思想: 在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。编程中的函数,也有类似的概念,你调用我的时候,给我实参为形参赋值,然后通过运行方法体,给你返回一个结果。对于调用者来做,关注这个方法具备什么样的功能。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是谁来做

 @Test
    public void test1(){
        String[] arr = {"hello","java","hi","xiao","yu"};
        //把上面的字符串按照长短排序,从短到长
//        Arrays.sort(arr);//按照编码排序
        //public static <T> void sort(T[] a, Comparator<? super T> c)
        Arrays.sort(arr, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
//                return o1.length()-o2.length();
                return Integer.compare(o1.length(), o2.length());
            }
        });
        /*
        上面的写法使用了匿名内部类,既声明了一个类,又创建了一个对象。
        创建这个对象的目的是为了给sort方法的第二个形参c赋值。
        声明匿名内部类的目的是为了重写public int compare(String o1, String o2)
         */
        System.out.println(Arrays.toString(arr));
    }
  //这个需求中我们关心的是什么? 如何比较两个字符串的大小,至于对象不重要
        Arrays.sort(arr, (o1, o2) -> Integer.compare(o1.length(), o2.length()));
        System.out.println(Arrays.toString(arr));

做什么,而不是谁来做,怎么做

我们真的希望创建一个匿名内部类对象吗?不。我们只是为了做这件事情而不得不创建一个对象。我们真正希望做的事情是:将compareTo方法体内的代码传递给sort方法知晓。

传递一段代码——这才是我们真正的目的。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。使用Lambda表达式不再有“不得不创建接口对象”的束缚,就是这么简单!

一、函数接口的概念

Lambda表达式其实就是实现SAM接口的语法糖,所谓SAM接口就是Single Abstract Method,即该接口中只有一个抽象方法需要实现,当然该接口可以包含其他非抽象方法(可以包含默认方法,静态方法,也就是实现此接口的子类只要求实现一个方法)。只要满足“SAM”特征的接口都可以称为函数式接口,都可以使用Lambda表达式,但是如果要更明确一点,最好在声明接口时,加上 @FunctionalInterface. 一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。

虽然Iterable和Comparable接口也只有一个抽象方法,但它们没有@FunctionalInterface注解标记,因此不算。

序号接口抽象方法SAM接口
1java.lang.Runnablepublic void run()
2java.util.Comparatorpublic int compare(T t1, T t2)
3java.io.FileFilterpublic boolean accept(File pathname)
4java.io.FilenameFilterpublic boolean accept(File dir, String name)

Lambda表达式语法格式

(形参列表) -> {Lambda体}

Lambda表达式的简化

  • 当{Lambda体}中只有一句语句时,可以省略{}和{;}
  • 当{Lambda体}中只有一句语句时,并且这个语句还是一个return语句,那么{、return、;}三者可以省略。它们三要么一起省略,要么都不省略。
  • 当Lambda表达式(形参列表)的类型已知,获取根据泛型规则可以自动推断,那么(形参列表)的数据类型可以省略。
  • 当Lambda表达式(形参列表)的形参个数只有一个,并且类型已知或可以自动推断,则形参的数据类型和()可以一起省略,但是形参名不能省略。
  • 当Lambda表达式(形参列表)是空参时,()不能省略

二、Java8之后引入的函数式接口

Java8在java.util.function新增了很多函数式接口:主要分为四大类,消费型、供给型、判断型、功能型。

1、消费型接口
有形参,但是返回值类型是void

序号接口名抽象方法描述
1Consumervoid accept(T t)接收一个对象用于完成功能
2BiConsumer<T,U>void accept(T t, U u)接收两个对象用于完成功能
3DoubleConsumervoid accept(double value)接收一个double值
4IntConsumervoid accept(int value)接收一个int值
5LongConsumervoid accept(long value)接收一个long值
6ObjDoubleConsumervoid accept(T t, double value)接收一个对象和一个double值
7ObjIntConsumervoid accept(T t, int value)接收一个对象和一个int值
8ObjLongConsumervoid accept(T t, long value)接收一个对象和一个long值

常用的方法:

public default void forEach(Consumer<? super T> action) 该方法功能是遍历Collection集合,并将传递给action参数的操作代码应用在每一个元素上。

 List<String> list = Arrays.asList("java","c","python","c++","VB","C#");
        list.forEach(s -> System.out.println(s));

2、供给型接口
无参,但是有返回值

序号接口名抽象方法描述
1SupplierT get()返回一个对象
2BooleanSupplierboolean getAsBoolean()返回一个boolean值
3DoubleSupplierdouble getAsDouble()返回一个double值
4IntSupplierint getAsInt()返回一个int值
5LongSupplierlong getAsLong()返回一个long值

3、判断型接口
有参,但是返回值类型是boolean结果。

序号接口名抽象方法描述
1Predicateboolean test(T t)接收一个对象
2BiPredicate<T,U>boolean test(T t, U u)接收两个对象
3DoublePredicateboolean test(double value)接收一个double值
4IntPredicateboolean test(int value)接收一个int值
5LongPredicateboolean test(long value)接收一个long值

常用的方法

public default boolean removeIf(Predicate<? super E> filter) 用于删除集合中满足filter指定的条件判断的。

   //删除包含o字母的元素
        list.removeIf(s -> s.contains("o"));

4、功能型接口
既有参数又有返回值

序号接口名抽象方法描述
1Function<T,R>R apply(T t)接收一个T类型对象,返回一个R类型对象结果
2UnaryOperatorT apply(T t)接收一个T类型对象,返回一个T类型对象结果
3DoubleFunctionR apply(double value)接收一个double值,返回一个R类型对象
4IntFunctionR apply(int value)接收一个int值,返回一个R类型对象
5LongFunctionR apply(long value)接收一个long值,返回一个R类型对象
6ToDoubleFunctiondouble applyAsDouble(T value)接收一个T类型对象,返回一个double
7ToIntFunctionint applyAsInt(T value)接收一个T类型对象,返回一个int
8ToLongFunctionlong applyAsLong(T value)接收一个T类型对象,返回一个long
9DoubleToIntFunctionint applyAsInt(double value)接收一个double值,返回一个int结果
10DoubleToLongFunctionlong applyAsLong(double value)接收一个double值,返回一个long结果
11IntToDoubleFunctiondouble applyAsDouble(int value)接收一个int值,返回一个double结果
12IntToLongFunctionlong applyAsLong(int value)接收一个int值,返回一个long结果
13LongToDoubleFunctiondouble applyAsDouble(long value)接收一个long值,返回一个double结果
14LongToIntFunctionint applyAsInt(long value)接收一个long值,返回一个int结果
15DoubleUnaryOperatordouble applyAsDouble(double operand)接收一个double值,返回一个double
16IntUnaryOperatorint applyAsInt(int operand)接收一个int值,返回一个int结果
17LongUnaryOperatorlong applyAsLong(long operand)接收一个long值,返回一个long结果
18BiFunction<T,U,R>R apply(T t, U u)接收一个T类型和一个U类型对象,返回一个R类型对象结果
19BinaryOperatorT apply(T t, T u)接收两个T类型对象,返回一个T类型对象结果
20ToDoubleBiFunction<T,U>double applyAsDouble(T t, U u)接收一个T类型和一个U类型对象,返回一个double
21ToIntBiFunction<T,U>int applyAsInt(T t, U u)接收一个T类型和一个U类型对象,返回一个int
22ToLongBiFunction<T,U>long applyAsLong(T t, U u)接收一个T类型和一个U类型对象,返回一个long
23DoubleBinaryOperatordouble applyAsDouble(double left, double right)接收两个double值,返回一个double结果
24IntBinaryOperatorint applyAsInt(int left, int right)接收两个int值,返回一个int结果
25LongBinaryOperatorlong applyAsLong(long left, long right)接收两个long值,返回一个long结果

常用的方法

default void replaceAll(UnaryOperator operator)将该列表的每个元素替换为将该运算符应用于该元素的结果。

 //使用Lambda表达式实现Function<T,R>接口的子接口UnaryOperator<T>,
        // 可以实现将一个字符串首字母转为大写的功能。
        list.replaceAll(s -> s.substring(0,1).toUpperCase() + s.substring(1));

5、自定义函数式接口
只要确保接口中有且仅有一个抽象方法即可:

修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数信息);
// 其他非抽象方法内容
}

接口当中抽象方法的 public abstract 是可以省略的

案例:

  • 声明一个转换器Convertor<T,R>,包含抽象方法change,可以将参数转换为另一个值,并返回结果。其中T是参数类型,R是返回值类型。
@FunctionalInterface
public interface Convertor<T,R> {
    R change(T t);
}
  //使用Lambda表达式实现Convertor接口,实现取字符串的首字母的功能
        Convertor<String,Character> c1 = (String str)-> {return str.charAt(0);};
        System.out.println(c1.change("hello"));

三、方法引用与构造器引用

Lambda表达式是可以简化函数式接口的变量与形参赋值的语法。而方法引用和构造器引用是为了简化Lambda表达式的。

当Lambda表达式满足一些特殊的情况时,还可以再简化:

(1)Lambda体只有一句语句,并且是通过调用一个对象的/类现有的方法来完成的

(2)并且Lambda表达式的形参正好全部用上,Lambda体中没有额外的数据参与

序号语法格式场景
1实例对象名::实例方法Lambda表达式有多个形参,Lambda体是调用Lambda体外的某个实例对象的实例方法完成,并且Lambda表达式的形参正好依次按顺序作为该方法调用的实参
2类名::静态方法Lambda表达式有多个形参,Lambda体是调用某个类的静态方法完成,并且Lambda表达式的形参正好依次按顺序作为该方法调用的实参
3类名::实例方法Lambda表达式只有1个形参,该参数正好Lambda体中调用方法的对象
Lambda表达式有多个形参,其中第1个参数正好是Lambda体中调用方法的对象,其余形参正好依次按顺序作为该方法调用的实参
4类名::new当Lambda表达式是一个new表达式,并且Lambda表达式形参正好依次按顺序作为所调用构造器的实参
5数组类型名::new当Lambda表达式是一个创建数组对象的new表达式,Lambda表达式的形参正好是创建数组的长度
List<Integer> list = Arrays.asList(1,3,4,8,9);
        //list.forEach(t -> System.out.println(t));
        //用方法引用再简化
        list.forEach(System.out::println);



//        File[] subFiles = dir.listFiles(sub->sub.isFile());
        File[] subFiles = dir.listFiles(File::isFile);

      //这个需求中我们关心的是什么? 如何比较两个字符串的大小,至于对象不重要
//        Arrays.sort(arr, (o1, o2) -> Integer.compare(o1.length(), o2.length()));
//        Arrays.sort(arr, Comparator.comparingInt(s->s.length()));
        Arrays.sort(arr, Comparator.comparingInt(String::length));


  Arrays.sort(arr, (s1,s2) -> s1.compareToIgnoreCase(s2));

        //用方法引用简化
        /*
         * Lambda表达式的形参,第一个(例如:s1),正好是调用方法的对象,剩下的形参(例如:s2)正好是给这个方法的实参
         */
        Arrays.sort(arr, String::compareToIgnoreCase);


 ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张三","李四","王五");
        //用list集合中的姓名,创建一个一个的Student对象
//        ArrayList<Student>

     /*   List<Student> result = list.stream()
                .map(name -> new Student(name)) //Function<T,R> R apply(T t)
                .collect(Collectors.toList());*/

        List<Student> result = list.stream()
                .map(Student::new) //Function<T,R> R apply(T t)
                .collect(Collectors.toList());

        result.forEach(System.out::println);


 Optional<Integer> opt1 = Optional.ofNullable(16);
//        Optional<String[]> opt2 = opt1.map(len -> new String[len]);
        Optional<String[]> opt2 = opt1.map(String[]::new);
        System.out.println(opt2.orElse(new String[0]).length);

四、Optional类

为了解决空指针异常
Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。

序号构造器或方法描述
1static Optional empty()用来创建一个空的Optional
2static Optional of(T value)用来创建一个非空的Optional
3static Optional ofNullable(T value)用来创建一个可能是空,也可能非空的Optional
4T get()返回Optional容器中的对象。要求Optional容器必须非空。T get()与of(T value)使用是安全的
5T orElse(T other)如果Optional容器中非空,就返回所包装值,如果为空,就用orElse(T other)other指定的默认值(备胎)代替。一般orElse(T other) 与ofNullable(T value)配合使用
6T orElseGet(Supplier<? extends T> other)如果Optional容器中非空,就返回所包装值,如果为空,就用Supplier接口的Lambda表达式提供的值代替
7 T orElseThrow(Supplier<? extends X> exceptionSupplier)如果Optional容器中非空,就返回所包装值,如果为空,就抛出你指定的异常类型代替原来的NoSuchElementException
8boolean isPresent()判断Optional容器中的值是否存在
9void ifPresent(Consumer<? super T> consumer)判断Optional容器中的值是否存在,如果存在,就对它进行Consumer指定的操作,如果不存在就不做
10 Optional map(Function<? super T,? extends U> mapper)判断Optional容器中的值是否存在,如果存在,就对它进行Function接口指定的操作,如果不存在就不做
//其他方法类似
String str = null;
        Optional<String> opt = Optional.ofNullable(str);
//		System.out.println(opt.get());//java.util.NoSuchElementException: No value present
        String string = opt.orElse("javaxiaoyu");
         System.out.println(string);   //javaxiaoyu

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/175.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot:手写一个 SpringBoot Starter

声明&#xff1a;原文作者&#xff1a;yuan_404 文章目录1. 说明2 . 编写启动器3 . 新建项目测试自己写的启动器1. 说明 启动器模块是一个 空 jar 文件&#xff0c;仅提供辅助性依赖管理&#xff0c;这些依赖可能用于自动装配或者其他类库 命名归约&#xff1a; 官方命名&…

面试必会-MySQL篇

1. Mysql查询语句的书写顺序Select [distinct ] <字段名称>from 表1 [ <join类型> join 表2 on <join条件> ]where <where条件>group by <字段>having <having条件>order by <排序字段>limit <起始偏移量,行数>2. Mysql查询语…

14个你需要知道的实用CSS技巧

让我们学习一些实用的 CSS 技巧&#xff0c;以提升我们的工作效率。这些 CSS 技巧将帮助我们开发人员快速高效地构建项目。 现在&#xff0c;让我们开始吧。 1.CSS :in-range 和 :out-of-range 伪类 这些伪类用于在指定范围限制之内和之外设置输入样式。 (a) : 在范围内 如…

SQL代码编码原则和规范

目录专栏导读1、先了解MySQL的执行过程2、数据库常见规范3、所有表必须使用Innodb存储引擎4、每个Innodb表必须有个主键5、数据库和表的字符集统一使用UTF86、查询SQL尽量不要使用select *&#xff0c;而是具体字段7、避免在where子句中使用 or 来连接条件8、尽量使用数值替代字…

植物大战 仿函数——C++

容器适配器 容器适配器不支持迭代器。栈这个东西&#xff0c;让你随便去遍历&#xff0c;是不好的。他是遵循后进先出的。所以他提供了一个街头top取得栈顶数据。 仿函数 仿函数&#xff08;functor&#xff09;是C中一种重载了函数调用运算符&#xff08;operator()&#x…

2023年网络安全最应该看的书籍,弯道超车,拒绝看烂书

学习的方法有很多种&#xff0c;看书就是一种不错的方法&#xff0c;但为什么总有人说&#xff1a;“看书是学不会技术的”。 其实就是书籍没选对&#xff0c;看的书不好&#xff0c;你学不下去是很正常的。 一本好书其实不亚于一套好的视频教程&#xff0c;尤其是经典的好书…

计算机网络概述

目录前言计算机网络的形成<font colorblue>计算机定义与分类计算机网络的定义计算机网络的分类1.按网络的覆盖范围分类2.按网络采用的传输技术分类按网络的拓扑分类计算机网络的组成计算机网络体系结构层次结构体系ISO/OSI 参考模型Tcp/ip体系结构这就是计算机网络的基础…

大数据框架之Hadoop:MapReduce(五)Yarn资源调度器

Apache YARN (Yet Another Resource Negotiator) 是 hadoop 2.0 引入的集群资源管理系统。用户可以将各种服务框架部署在 YARN 上&#xff0c;由 YARN 进行统一地管理和资源分配。 简言之&#xff0c;Yarn是一个资源调度平台&#xff0c;负责为运算程序提供服务器运算资源&…

Linux- 系统随你玩之--玩出花活的命令浏览器上

文章目录1、背景2、命令浏览器2.1、命令浏览器介绍2.2、特点2.3 常用功能选项3、实操3.1、使用 wget 下载文件3.2、 断点续传3.3、镜像整个站点4、 总结1、背景 一位友人说他有台服务器&#xff0c;需要下载一个文件&#xff0c;但是没有视窗界面与下载工具&#xff0c;怎么办…

自动写代码?别闹了!

大家好&#xff0c;我是良许。 这几天&#xff0c;GitHub 上有个很火的插件在抖音刷屏了——Copilot。 这个神器有啥用呢&#xff1f;简单来讲&#xff0c;它就是一款由人工智能打造的编程辅助工具。 我们来看看它有啥用。 首先就是代码补全功能&#xff0c;你只要给出函数…

GEC6818开发板JPG图像显示,科大讯飞离线语音识别包Linux_aitalk_exp1227_1398d7c6运行demo程序,开发板实现录音

GEC6818开发板JPG图像显示 | 开发板实现录音一.GEC6818开发板JPG图像显示1.jpg图片特性2.如何解压缩jpg图片1.对jpegsrc.v8c.tar.gz进行arm移植2.进入~/jpeg-8c对jpeg库进行配置3.编译4.安装&#xff0c;将动态库存放到 /home/gec/armJPegLib5.清空编译记录6.自己查看下 /home/…

外卖点餐系统小程序 PHP+UniAPP

一、介绍 本项目是给某大学餐厅开发的外面点餐系统&#xff0c;该项目针对校内的学生&#xff0c;配送由学校的学生负责配送。因此&#xff0c;该项目不同于互联网的外卖点餐系统。 该系统支持属于 Saas 系统&#xff0c;由平台端、商家端、用户端、以及配送端组成。 其中&a…

学会这12个Python装饰器,让你的代码更上一层楼

学会这12个Python装饰器&#xff0c;让你的代码更上一层楼 Python 装饰器是个强大的工具&#xff0c;可帮你生成整洁、可重用和可维护的代码。某种意义上说&#xff0c;会不会用装饰器是区分新手和老鸟的重要标志。如果你不熟悉装饰器&#xff0c;你可以将它们视为将函数作为输…

2022-2-23作业

一、通过操作Cortex-A7核&#xff0c;串口输入相应的命令&#xff0c;控制LED灯进行工作 1.例如在串口输入led1on,开饭led1灯点亮 2.例如在串口输入led1off,开饭led1灯熄灭 3.例如在串口输入led2on,开饭led2灯点亮 4.例如在串口输入led2off,开饭led2灯熄灭 5.例如在串口输…

100天精通Python(可视化篇)——第77天:数据可视化入门基础大全(万字总结+含常用图表动图展示)

文章目录1. 什么是数据可视化&#xff1f;2. 为什么会用数据可视化&#xff1f;3. 数据可视化的好处&#xff1f;4. 如何使用数据可视化&#xff1f;5. Python数据可视化常用工具1&#xff09;Matplotlib绘图2&#xff09;Seaborn绘图3&#xff09;Bokeh绘图6. 常用图表介绍及其…

为什么很多计算机专业大学生毕业后还会参加培训?

基于IT互联网行业越来越卷的现状&#xff0c;就算是科班出身&#xff0c;很多也是达不到用人单位的要求。面对这样的现实情况&#xff0c;有的同学会选择继续深造&#xff0c;比如考个研&#xff0c;去年考研人数457万人次&#xff0c;可见越来越的同学是倾向考研提升学历来达到…

GH3018超低功耗、超高精度的心率传感器

GH3018是一款超低功耗、超高精度的心率传感器&#xff0c;集成了3路LED驱动器、一个光学接收器&#xff08;PD&#xff09;及模拟前端&#xff08;AFE&#xff09;&#xff0c;支持心率&#xff08;HR&#xff09;、心率变异性&#xff08;HRV&#xff09;、血氧饱和度&#xf…

Springboot——自定义Filter使用测试总结

文章目录前言自定义过滤器并验证关于排除某些请求的方式创建测试接口请求测试验证异常过滤器的执行流程注意事项资料参考前言 在Java-web的开发领域&#xff0c;对于过滤器和拦截器用处还是很多&#xff0c;但两者的概念却极易混淆。 过滤器和拦截器都是采用AOP的核心思想&am…

HTML 扫盲

✏️作者&#xff1a;银河罐头 &#x1f4cb;系列专栏&#xff1a;JavaEE &#x1f332;“种一棵树最好的时间是十年前&#xff0c;其次是现在” 目录前言HTML 结构快速生成代码框架HTML 常见标签注释标签标题标签: h1-h6段落标签&#xff1a;p换行标签&#xff1a;br格式化标签…

PTA第六章作业详解

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;夏目的作业 &#x1f4ac;总结&#xff1a;希望你看完之后&am…
最新文章