[Java基础]函数式编程

Lambda函数

JDK8新增的语法形式, 使用Lambda函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好。

基本使用

lambda表达式只能简化函数式接口的匿名内部类写法

// 1.定义抽象类
abstract class Animal {public abstract void crt();
}public class LambdaDome {public staitc void main(String[] args) {// 2.使用匿名内部类, 创建抽象类的子类对象Animal a = new Animal() {@Overridepublic void cry() {sout("猫喵喵的叫")}}// 3. 错误示范, 代码报错// lambda表达式并不能简写所有匿名内部类的写法Animal a = () -> {sout("猫喵喵的叫")}a.cry(); // 猫喵喵的叫}
}
// 1.定义函数式接口
// 定义: 有且只有一个抽象方法的接口称为函数式接口
// 注解: 约束函数式接口的注解, 不符合要求会报错
@FunctionalInterface
interface Swim {void swimming();
}public class LambdaDome {public staitc void main(String[] args) {// 2.使用匿名内部类, 创建接口类的子类对象Swim a = new Swim() {@Overridepublic void swimming() {sout("老师狗爬式游泳")}}// 3. 使用lambda表达式简化匿名内部类写法Swim a = () -> {sout("老师狗爬式游泳")}a.swimming(); // 老师狗爬式游泳}
}
  1. 什么是函数式接口? 有且仅有一个抽象方法的接口。
  2. 大部分函数式接口,上面都会有 @Functionallnterface 注解, 用于约束当前接口必须是函数式接口。

简化规则

用于进一步简化Lambda表达式的写法。

  1. 参数类型全部可以省略不写。
  1. 如果只有一个参数, “()”也可以省略,但多个参数不能省略
  2. 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号“;”
  3. 如果这行代码是return语句,也必须去掉return。
public class Test {public static void main(String[] args) {// 需求: 创建一个登录窗口,窗口上有一个登录按钮JFrame win = new JFrame("登录窗口");win.setSize(300, 200);win.setLocationRelativeTo(null); // 居中展示win.setDefaultCloseOperaion(JFrame.EXIT_ON_CLOSE);JPanel penel new JPanel();win.add(penel);JButton btn = new JButton("登录");// 2.匿名内部类: 快速创建对象, 传给方法// btn.addActionListener(new ActionListener{//       public void actionPerfirmed(ActionEvent e) {//          sout("按钮点击了")//       }// });// 3. 使用lambda表达式的规则简化语法btn.addActionListener(e -> sout("按钮点击了"));win.setVisible(true);}
}
public class Test {public static void main(String[] args) {// 需求: 完成数组排序, 加深匿名内部类的使用// 1. 准备数组,存放学生对象student[] students = new student[4];students[0] = new Student( name:"殷素素",age:35,height:171.5,sex:'女');students[1] = new Student( name:"杨幂",age:28,height: 168.5,sex:'女');students[2] = new student( name:"张无忌"age:25,height:181.5,sex:'男');students[3] = new student( name:"刘亦菲",age: 36,height: 168,sex:'女');// 2.使用数组的API, 对数组按照对象的年龄升序排序// Arrays.sort(students, new Comparator<Student>() {//     @Override//     public int compare(Student o1, Student o2) {//         // 按对象年龄升序排序//         return o1.getAge() - o2.getAge();//         // 按对象年龄降序排序//         return o2.getAge() - o1.getAge();//     }// });//3.使用lambda表达式的规则简化语法Arrays.sort(students, (o1,o2) -> o1.getAge() - o2.getAge());// 3.遍历数组中的对象并输出for (int i = 0; i<students.length; i++) {student s = students[i];sout(s);}}
}

方法引用

进一步简化Lambda表达式, 遇到可以简化场景时使用(IDEA会提示)

静态方法引用

类名::静态方法

如果某个Lambda表达式里只是调用一个静态方法, 并且 "->"前后参数的形式一致, 就可以使用静态方法引用

public class Student {private String name;private int age;private double height;private String sex;// 提供静态方法public static int compareByAge(Student s1, Student s2) {return s1.getAge() - s2.getAge()}
}public class Test {public static void main(String[] args) {// 1. 准备数组,存放学生对象student[] students = new student[4];students[0] = new Student( name:"殷素素”,age:35,height:171.5,sex:'女');students[1] = new Student( name:"杨幂",age:28,height: 168.5,sex:'女');students[2] = new student( name:"张无忌"age:25,height:181.5,sex:'男');students[3] = new student( name:"刘亦菲",age: 36,height: 168,sex:'女');// 2.使用数组的API, 对数组按照对象的年龄升序排序// Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());// 3.使用lambda表达式调用静态方法// Arrays.sort(students, (o1, o2) -> Student.compareByAge(o1, o2));// 3.使用静态方法引用进一步简化Arrays.sort(students, Student::compareByAge);// 4.遍历数组中的对象并输出for (int i = 0; i<students.length; i++) {student s = students[i];sout(s);}}
}

实例方法引用

对象名::实例方法

如果某个Lambda表达式里只是调用一个实例方法, 并且"->"前后参数的形式一致, 就可以使用实例方法引用

public class Student {private String name;private int age;private double height;private String sex;// 提供实例方法public int compareByAge(Student s1, Student s2) {return s1.getAge() - s2.getAge()}
}public class Test {public static void main(String[] args) {// 1. 准备数组,存放学生对象student[] students = new student[4];students[0] = new Student( name:"殷素素”,age:35,height:171.5,sex:'女');students[1] = new Student( name:"杨幂",age:28,height: 168.5,sex:'女');students[2] = new student( name:"张无忌"age:25,height:181.5,sex:'男');students[3] = new student( name:"刘亦菲",age: 36,height: 168,sex:'女');// 2.使用数组的API, 对数组按照对象的年龄升序排序// Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());// 3.使用lambda表达式调用实例方法Student s1 = new Student();// Arrays.sort(students, (o1, o2) -> s1.compareByAge(o1,o2));// 3.使用实例方法引用进一步简化Arrays.sort(students, s1::compareByAge);// 4.遍历数组中的对象并输出for (int i = 0; i<students.length; i++) {student s = students[i];sout(s);}}
}

特定类型的方法引用

特定类的名称::方法

如果某个Lambda表达式里只是调用一个特定类型的实例方法, 并且前面参数列表中的第一个参数作为方法的主调, 后面的所有参数都是作为该实例方法的入参, 此时可以使用特定类型的方法引用

public class Demo {public static void main(String[] args) {// 需求:有一个字符申数组,里面有一些人的名字都是,请按照名字的首字母升序排序String[] names = {"Tom", "Jerry", "Bobi", "曹操", "Mike", "angela", "Dlei", "Jack", "Rose", "Andy", "caocao"};// 1.对数组排序: Arrays.sort(数组, 比较器对象)Arrays.sort(names);  // 默认就是按照首字母的编号升序排序System.out.println(Arrays.toString(names)); // [Andy, Bobi, Jack, Jerry, Mike, Rose, Tom, angela, caocao, 曹操, Dlei]// 2.需要忽略首字母的大小写进行升序排序(java官网默认是搞不定的,需要自己指定比较规则)Arrays.sort(names, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareToIgnoreCase(o2); // java提供了字符串按照首字母忽略大小写比较的方法}});System.out.println(Arrays.toString(names)); // [Andy, angela, Bobi, caocao, Dlei, Jack, Jerry, Mike, Rose, Tom, 曹操]// 3.使用特定类型的方法引用简化代码Arrays.sort(names, String::compareToIgnoreCase);System.out.println(Arrays.toString(names)); // [Andy, angela, Bobi, caocao, Dlei, Jack, Jerry, Mike, Rose, Tom, 曹操]}
}

构造器引用

类名::new

如果某个Lambda表达式里只是在创建对象, 并且"->"前后参数情况一致, 就可以使用构造器引用

// 汽车类
class Car {private String name;
}// 函数式接口
@FunctionalInterface
interface CarFactory {Car getCar(String name);
}public class Demo {public static void main(String[] args) {// 1.创建接口的匿名内部类对象CarFactory cf = new CarFactory() {@Overridepublic Car getCar(String name) {return new Car(name);}}// 2.使用lambda表达式简写CarFactory cf = name -> new Car(name);// 3.构造器引用进一步简化CarFactory cf = Car::new;Car c1 = cf.getCar("奔驰");System.out.println(c1); // Car(name=奔驰)}
}

Stream流

认识流

Jdk8开始新增的一套API(iava.util.stream.*),可以用于操作集合或者数组的数据

  1. 先得到集合或者数组的Stream流。
  2. 然后调用Stream流的方法对数据进行处理。
  3. 获取处理的结果。

示例代码

public class Dome {public static void main(String[] args) {// 1.认识stream流的使用// 需求: 把集合中所有以“张”开头,且是3个字的元素存储到一个新的集合ArrayList<String> list = new ArrayList<>();list.add("张无忌");list.add("周芷若");list.add("赵敏");list.add("张强");list.add("张三丰");// 2.使用传统方式完成需求List<String> newList = new ArrayList<>();for (String l : list) {if (l.startsWith("张") && l.length() == 3) {newList.add(l);}}// [张无忌, 张三丰]System.out.println(newList);// 3.使用stream流完成需求List<String> newList2 = list.stream().filter(l -> l.startsWith("张")).filter(l -> l.length() == 3).collect(Collectors.toList());// [张无忌, 张三丰]System.out.println(newList2);}
}
  1. Stream流大量的结合了Lambda的语法风格来编程,功能强大,性能高效,代码简洁,支持链式编程

获取流

1.获取集合的Stream流

public class Dome2 {public static void main(String[] args) {// 获取Stream流// 1.获取Collection集合流// 使用Collection接口提供的stream()方法获取流Collection<String> list = new ArrayList<>();Stream<String> s1 = list.stream();// 2.获取Map集合流Map<String, Integer> map = new HashMap<>();// 获取键流Stream<String> s2 = map.keySet().stream();// 获取值流Stream<Integer> s3 = map.values().stream();// 获取键值对流Stream<Map.Entry<String, Integer>> s4 = map.entrySet().stream();}
}
2.获取数组的Stream流

public class Dome2 {public static void main(String[] args) {// 获取Stream流String[] arr = {"a", "b", "c", "d"};// 3.获取数组流// 使用Stream类中的静态方法of()Stream<String> s5 = Stream.of(arr);// 使用Arrays类中的静态方法stream()Stream<String> s6 = Arrays.stream(arr);}
}

处理流

中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程),

public class Dome3 {public static void main(String[] args) {// 使用stream流的中间方法处理数据ArrayList<String> list = new ArrayList<>();list.add("张无忌");list.add("周芷若");list.add("赵敏");list.add("张强");list.add("张三丰");// 1.过滤方法list.stream().filter(s -> s.startsWith("张") && s.length() == 3).forEach(System.out::println); // 张无忌, 张三丰// 2.排序方法List<Double> scores = new ArrayList<>();scores.add(99.9);scores.add(66.1);scores.add(88.7);scores.add(66.1);scores.add(72.3);scores.add(88.7);// 默认是升序排序  66.1 72.3 88.7 99.9scores.stream().sorted().forEach(System.out::println);// 指定排序规则(降序) 99.9 88.7 72.3 66.1scores.stream().sorted((o1, o2) -> Double.compare(o2, o1)).forEach(System.out::println);// 3.截取方法,// 只要前3名 99.9 88.7 72.3scores.stream().sorted((o1, o2) -> Double.compare(o2, o1)).limit(3).forEach(System.out::println);// 跳过前2名 72.3 66.1scores.stream().sorted((o1, o2) -> Double.compare(o2, o1)).skip(2).forEach(System.out::println);// 4.去重方法 99.9 66.1 88.7 72.3// 如果自定义对象需要去重, 该对象必须重写hashCode和equals方法scores.stream().distinct().forEach(System.out::println);// 5.映射/加工方法: 把流里面的元素进行加工, 得到新的集合// 成绩是:99.9分 成绩是:66.1分 成绩是:88.7分 成绩是:66.1分 成绩是:72.3分 成绩是:88.7分scores.stream().map(s -> "成绩是:" + s + "分").forEach(System.out::println);// 6.合并流Stream<String> s1 = Stream.of("张无忌", "赵敏", "张三丰");Stream<Integer> s2 = Stream.of(11, 22, 31);Stream<Object> s3 = Stream.concat(s1, s2);System.out.println(s3.count()); // 6}
}

终结流

使用Stream是为了方便的操作集合和数组, 操作完成后把结果收集到数组或集合中, 才是最终的目的

  1. 终结流

  • 补充: Optional容器中的元素需要通过get()方法获取出来

  1. 收集流

代码示例

public class Teacher {private String name;private int age;private double salary;//... 省略构造器和get/set方法 ...@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +", salary=" + salary +'}' + '\n';}
}
public class Dome4 {public static void main(String[] args) {// 掌握终结Stream流的方法List<Teacher> list = List.of(new Teacher("张三", 18, 5000),new Teacher("李四", 28, 6000),new Teacher("王五", 38, 7000),new Teacher("赵六", 48, 8000));// 1.遍历终结// Teacher{name='王五', age=38, salary=7000.0} Teacher{name='赵六', age=48, salary=8000.0}list.stream().filter(t -> t.getSalary() > 6000).forEach(System.out::println);// 2.获取结果数量long count = list.stream().filter(t -> t.getSalary() > 6000).count();System.out.println(count); // 2// 3.获取最大值 (根据工资)Teacher max = list.stream().max(Comparator.comparing(Teacher::getSalary)).get();System.out.println(max); // Teacher{name='赵六', age=48, salary=8000.0}// 4.获取最小值 (根据年龄)Teacher min = list.stream().min(Comparator.comparing(Teacher::getAge)).get();System.out.println(min); // Teacher{name='张三', age=18, salary=5000.0}}
}
public class Dome5 {public static void main(String[] args) {// 掌握收集Stream流的方法List<Teacher> list = List.of(new Teacher("张三", 18, 5000),new Teacher("李四", 28, 6000),new Teacher("王五", 38, 7000),new Teacher("赵六", 48, 8000));// 1. 把流收集到list集合中List<Teacher> list1 = list.stream().filter(s -> s.getName().startsWith("张")).collect(Collectors.toList());System.out.println(list1); // [Teacher{name='张三', age=18, salary=5000.0}]// 2. 把流收集到set集合中Set<Teacher> list2 = list.stream().filter(s -> s.getName().startsWith("张")).collect(Collectors.toSet());System.out.println(list2);// [Teacher{name='张三', age=18, salary=5000.0}]// 3. 把流收集到数组中Object[] list3 = list.stream().filter(s -> s.getName().startsWith("张")).toArray();System.out.println(Arrays.toString(list3)); // [Teacher{name='张三', age=18, salary=5000.0}]// 4. 把流收集到Map集合中: 键是老师的名字, 值是老师的薪水// 4.1完整写法
//        Map<String, Double> map = list.stream().collect(Collectors.toMap(new Function<Teacher, String>() {
//            @Override
//            public String apply(Teacher teacher) {
//                return teacher.getName();
//            }
//        }, new Function<Teacher, Double>() {
//            @Override
//            public Double apply(Teacher teacher) {
//                return teacher.getSalary();
//            }
//        }));// 4.2lambda简写
//        Map<String, Double> map = list.stream().
//                collect(Collectors.toMap(teacher -> teacher.getName(), teacher -> teacher.getSalary()));// 4.3方法引用简写Map<String, Double> map = list.stream().collect(Collectors.toMap(Teacher::getName, Teacher::getSalary));System.out.println(map); // {李四=6000.0, 张三=5000.0, 王五=7000.0, 赵六=8000.0}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vim 多窗口编辑及文件对比

水平分割 :split 默认使用水平分割的方式。 :split :sp 垂直分割 :vsplit :vs 带文件的分割 :split 文件名 :sp 文件名 在光标所在的窗口&#xff0c;输入分割窗口命令就会对那个窗口进行分割。 切换窗口 Ctrlw 切换正在编辑的窗口 快速分割窗口 Ctrlwn 快速分割当前…

二级C语言题解:十进制转其他进制、非素数求和、重复数统计

目录 一、程序填空&#x1f4dd; --- 十进制转其他进制 题目&#x1f4c3; 分析&#x1f9d0; 二、程序修改&#x1f6e0;️ --- 非素数求和 题目&#x1f4c3; 分析&#x1f9d0; 三、程序设计&#x1f4bb; --- 重复数统计 题目&#x1f4c3; 分析&#x1f9d0; 前言…

使用服务器部署DeepSeek-R1模型【详细版】

文章目录 引言deepseek-r1IDE或者终端工具算力平台体验deepseek-r1模型总结 引言 在现代的机器学习和深度学习应用中&#xff0c;模型部署和服务化是每个开发者面临的重要任务。无论是用于智能推荐、自然语言处理还是图像识别&#xff0c;如何高效、稳定地将深度学习模型部署到…

央行发布《贸易金融分布式账本技术要求》,参考架构包括5部分

《银行科技研究社》(作者 木子剑):2024年12月11日,中国人民银行发布金融行业标准《贸易金融分布式账本技术要求》(JR/T 0308-2024)(以下简称“《要求》”),当日实施。据悉,该文件的起草单位包括6大行和多家股份制银行等。 《要求》规定了分布式账本技术在贸易金融领域…

Python aiortc API

本研究的主要目的是基于Python aiortc api实现抓取本地设备媒体流&#xff08;摄像机、麦克风&#xff09;并与Web端实现P2P通话。本文章仅仅描述实现思路&#xff0c;索要源码请私信我。 1 demo-server解耦 1.1 原始代码解析 1.1.1 http服务器端 import argparse import …

记录 | WPF基础学习Style局部和全局调用

目录 前言一、Style1.1 例子1.2 为样式起名字1.3 BasedOn 继承上一个样式 二、外部StyleStep1 创建资源字典BaseButtonStyle.xamlStep2 在资源字典中写入StyleStep3 App.xaml中写引用路径【全局】Step4 调用三、代码提供四、x:Key和x:Name区别 更新时间 前言 参考文章&#xff…

吴恩达深度学习——卷积神经网络实例分析

内容来自https://www.bilibili.com/video/BV1FT4y1E74V&#xff0c;仅为本人学习所用。 文章目录 LeNet-5AlexNetVGG-16ResNets残差块 1*1卷积 LeNet-5 输入层&#xff1a;输入为一张尺寸是 32 32 1 32321 32321的图像&#xff0c;其中 32 32 3232 3232是图像的长和宽&…

【Uniapp-Vue3】z-paging插件组件实现触底和下拉加载数据

一、下载z-paing插件 注意下载下载量最多的这个 进入Hbuilder以后点击“确定” 插件的官方文档地址&#xff1a; https://z-paging.zxlee.cn 二、z-paging插件的使用 在文档中向下滑动&#xff0c;会有使用方法。 使用z-paging标签将所有的内容包起来 配置标签中的属性 在s…

【B站保姆级视频教程:Jetson配置YOLOv11环境(七)Ultralytics YOLOv11配置】

Jetson配置YOLOv11环境&#xff08;7&#xff09;Ultralytics YOLOv11环境配置 文章目录 1. 下载YOLOv11 github项目2. 安装ultralytics包3. 验证ultralytics安装3.1 下载yolo11n.pt权重文件3.2 推理 1. 下载YOLOv11 github项目 创建一个目录&#xff0c;用于存放YOLOv11的项目…

第二天:系统从BIOS/UEFI到GRUB/bootloader的启动过程

目录 **一、BIOS/UEFI初始化阶段****二、引导加载程序&#xff08;GRUB&#xff09;的启动过程****1. BIOS模式下的GRUB分阶段加载****2. UEFI模式下的GRUB加载** **三、操作系统内核加载与初始化****四、关键组件与配置文件****五、故障排查与恢复****总结**常见问题如何在UEF…

【容器技术01】使用 busybox 构建 Mini Linux FS

使用 busybox 构建 Mini Linux FS 构建目标 在 Linux 文件系统下构建一个 Mini 的文件系统&#xff0c;构建目标如下&#xff1a; minilinux ├── bin │ ├── ls │ ├── top │ ├── ps │ ├── sh │ └── … ├── dev ├── etc │ ├── g…

【C语言系列】深入理解指针(5)

深入理解指针&#xff08;5&#xff09; 一、sizeof和strlen的对比1.1sizeof1.2strlen1.3sizeof和strlen的对比 二、数组和指针笔试题解析2.1 一维数组2.2 字符数组2.2.1代码1&#xff1a;2.2.2代码2&#xff1a;2.2.3代码3&#xff1a;2.2.4代码4&#xff1a;2.2.5代码5&#…

【蓝桥杯嵌入式】2_LED

1、电路图 74HC573是八位锁存器&#xff0c;当控制端LE脚为高电平时&#xff0c;芯片“导通”&#xff0c;LE为低电平时芯片“截止”即将输出状态“锁存”&#xff0c;led此时不会改变状态&#xff0c;所以可通过led对应的八个引脚的电平来控制led的状态&#xff0c;原理图分析…

Diskgenius系统迁移之后无法使用USB启动

前言 本文用于记录系统迁移中遇到的问题及解决方法&#xff0c;如有不对请指出&#xff0c;谢谢&#xff01; 现象 使用DiskGenius进行系统迁移后&#xff0c;使用USB启动失败&#xff0c;反复在品牌logo和黑屏之间切换&#xff0c;期间还会在左上角显示”reset system“报错…

SQL Server 数据库备份指南

SQL Server备份是数据库维护的日常工作。备份的目的是在发生数据丢失、损坏甚至硬件故障时将数据库和事务日志恢复到最近的时间点。您可以借助专业的SQL Server备份软件,操作起来更方便。前提需要安装SQL Server Management Studio (SSMS)工具。 对于 SQL 数据库备份,有多种…

SpringAI介绍及本地模型使用方法

博客原文地址 前言 Spring在Java语言中一直稳居高位&#xff0c;与AI的洪流碰撞后也产生了一些有趣的”化学反应“&#xff0c;当然你要非要说碰撞属于物理反应也可以&#xff0c; 在经历了一系列复杂的反应方程后&#xff0c;Spring家族的新成员——SpringAI&#xff0c;就…

ip地址是手机号地址还是手机地址

在数字化生活的浪潮中&#xff0c;IP地址、手机号和手机地址这三个概念如影随形&#xff0c;它们各自承载着网络世界的独特功能&#xff0c;却又因名称和功能的相似性而时常被混淆。尤其是“IP地址”这一术语&#xff0c;经常被错误地与手机号地址或手机地址划上等号。本文旨在…

车载以太网__传输层

车载以太网中&#xff0c;传输层和实际用的互联网相差无几。本篇文章对传输层中的IP进行介绍 目录 什么是IP&#xff1f; IP和MAC的关系 IP地址分类 私有IP NAT DHCP 为什么要防火墙穿透&#xff1f; 广播 本地广播 直接广播 本地广播VS直接广播 组播 …

wxWidgets生成HTML文件,带图片转base64数据

编译环境大家可以看我之前的文章,CodeBlocks + msys2 + wx3.2,win10 这里功能就是生成HTML文件,没用HTML库,因为是自己固定的格式,图片是一个vector,可以动态改变数量的。 效果如下: #include <wx/string.h> #include <wx/file.h> #include <wx/ima…

网络原理一>数据链路层协议->以太网协议

目录 以太网协议的结构&#xff1a;类型&#xff1a;ARP请求应答报文&#xff1a;CRC&#xff1a;MTU: 为什么需要mac地址&#xff1a;mac地址和IP地址的区别&#xff1a; 以太网协议的结构&#xff1a; 以太网是数据链路层和物理层的主要协议 源IP&#xff0c;目的IP就不多说…