当前位置: 首页 > backend >正文

Lambda表达式Stream流

一、Lambda表达式

2.1 概述

Lambda是IDK8中一个语法糖。他可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什
么对象。而是更关注我们对数据进行了什么操作。

2.2 基本格式

(参数列表)->{代码}

例一

我们在创建线程并启动时可以使用匿名内部类的写法:

new Thread(new Runnable(){@overridepublic void run(){System.out.printin("你知道吗 我比你	想象的 更想在你身边”);
}).start();

可以使用Lambda的格式对其进行修改:

new Thread(()->{System.out.print]n("你知道吗 我比你想象的 更想在你身边");}).start();

2.3 省略规则

  • 参数类型可以省略
  • 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
  • 方法只有一个参数时小括号可以省略
  • 以上这些规则都记不住也可以省略不记

二、Stream流

2.1 概述

Java8的stream使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合或数组进行链状流式的操作。可以更方便的让我们
对集合或数组操作。

2.2 案例准备

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Author {
//id
private Long id;
//姓名
private String name;
//年龄
private Integer age;//简介
private String intro;
//作品
private List<Book> books ;
}
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Book {private Long id;private String name;private String category;private Integer score;private String intro;
}
public class StreamDemo {private static List<Author> getAuthors() {// 数据初始化Author author = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);Author author2 = new Author(2L, "亚拉索", 15, "狂风也追逐不上他的思考速度", null);Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);// 修正:将重复ID的作者改为唯一IDAuthor author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);// 书籍列表List<Book> books1 = new ArrayList<>();List<Book> books2 = new ArrayList<>();List<Book> books3 = new ArrayList<>();books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用一把刀划分了爱恨"));books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长,爱情", 99, "讲述如何从失败中明悟真理"));books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));// 修正:移除重复的书籍// books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));books2.add(new Book(4L, "吹或不吹", "爱情,个人传记", 56, "一个哲学家的恋爱观注定很难把他所在的时代理解"));books3.add(new Book(5L, "你的剑就是我的剑", "爱情", 56, "无法想象一个武者能对他的伴侣这么的宽容"));books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));// 修正:移除重复的书籍// books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));author.setBooks(books1);author2.setBooks(books2);author3.setBooks(books3);author4.setBooks(books3);//Arrays.asList() 是 Java 标准库中的一个静态方法,用于将一组元素转换为一个固定大小的列表。// 这里它将四个 Author 对象转换为列表,并作为参数传递给 ArrayList 的构造函数。List<Author> authorList = new ArrayList<>(Arrays.asList(author, author2, author3, author4));return authorList;}
}

2.3 快速入门

2.3.1 需求

我们可以调用getAuthors方法获取到作家的集合。现在需要打印所有年龄小于18的作家的名字,并且要注意去重。

代码实现
public static void main(String[] args) {List<Author> authors = getAuthors();authors.stream()//要把集合先转换成stream对象.distinct()//去重.filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getAge() < 18;}}).forEach(new Consumer<Author>() {@Overridepublic void accept(Author author) {System.out.println(author.getName());}});
}

2.4 常用操作

2.4.1 创建流

单列集合:集合对象.stream()

List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();

数组:Arrays.stream(数组)或者使用Stream.of来创建

Integer[] arr = {1,2,3,4,5};
Stream<Integer> stream = Arrays.stream(arr);
Stream<Integer> arr1 = Stream.of(arr);

双列集合:转换成单列集合后再创建

private static void test04() {HashMap<String, Integer> map = new HashMap<>();map.put("蜡笔小新",19);map.put("黑子",17);map.put("迪迦",14);Set<Map.Entry<String, Integer>> entries = map.entrySet();Stream<Map.Entry<String, Integer>> stream = entries.stream();stream.filter(entry -> entry.getValue() > 15).forEach(new Consumer<Map.Entry<String, Integer>>() {@Overridepublic void accept(Map.Entry<String, Integer> entry) {System.out.println(entry.getKey() + " : "+entry.getValue());}});
}

2.4.2 中间操作

filter

可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中。

map

可以把对流中的元素进行计算或转换。

private static void test04() {HashMap<String, Integer> map = new HashMap<>();map.put("蜡笔小新",19);map.put("黑子",17);map.put("迪迦",14);Set<Map.Entry<String, Integer>> entries = map.entrySet();Stream<Map.Entry<String, Integer>> stream = entries.stream();stream.filter(entry -> entry.getValue() > 15).forEach(new Consumer<Map.Entry<String, Integer>>() {@Overridepublic void accept(Map.Entry<String, Integer> entry) {System.out.println(entry.getKey() + " : "+entry.getValue());}});
}
distinct

可以去除流中的重复元素

private static void test06() {List<Author> authors = getAuthors();authors.stream().distinct().forEach(a -> System.out.println(a.getName()));
}

需要注意的是,去重时是通过Object的equals方法来实现的。

在这里插入图片描述

实际操作时可以通过给实体类添加**@EqualsAndHashCode**来实现

sorted

可以对流中的元素进行排序。

例如:

对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素。

private static void test07() {List<Author> authors = getAuthors();authors.stream().distinct().sorted((o1, o2) -> o2.getAge() - o1.getAge()).forEach(author -> System.out.println(author.getName() +" 的年龄是"+ author.getAge()));
}

sorted有空参和有参两个重载形式,空参要求元素实现了Comparable接口,有参要求传入Comparator。

limit

可以设置流的最大长度,超出的部分将被抛弃

例如:

对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名。

private static void test08() {List<Author> authors = getAuthors();authors.stream().distinct().sorted((o1, o2) -> o2.getAge() - o1.getAge()).limit(2).forEach(author -> System.out.println(author.getName() +" 的年龄是"+ author.getAge()));}
skip

跳过流中的前n个元素,返回剩下的元素

例如:

打印除了年龄最大的作家外的其他作家,要求不能有重复元素,并且按照年龄降序排序。

private static void test09() {List<Author> authors = getAuthors();authors.stream().distinct().sorted((o1,o2) -> o2.getAge()-o1.getAge()).skip(1).forEach(a -> System.out.println(a.getName() + "的年龄是" + a.getAge()));
}
flatMap

map只能把一个对象转换成另一个对象来作为流中的元素。二flatMap可以把一个对象转换成多个对象作为流中的元素。

例一:

打印所有书籍的名字,要求对重复的元素进行去重。

//匿名内部类
private static void test10() {List<Author> authors = getAuthors();authors.stream().flatMap(new Function<Author, Stream<Book>>() {@Overridepublic Stream<Book> apply(Author author) {return author.getBooks().stream();}}).distinct().forEach(book -> System.out.println(book.getName()) );
}

例二:

打印现有数据的有分类。要求对分类进行去重。不能出现这种格式:哲学,爱情

private static void test11() {List<Author> authors = getAuthors();authors.stream().flatMap(author -> author.getBooks().stream()).distinct().flatMap(book -> Arrays.stream(book.getCategory().split(","))).distinct().forEach(s -> System.out.println(s));
}

2.4.3 终结操作

forEach

对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的元素进行什么具体操作。

count

可以用来获取当前流中元素的个数

例如:

打印这些作家的所出书籍的数目,注意删除重复元素

private static void test12() {List<Author> authors = getAuthors();long count = authors.stream().flatMap(author -> author.getBooks().stream()).distinct().count();System.out.println(count);
}
max&min

可以用来获取流中的最值

例子:分别获取这些作家的所出书籍的最高分和最低分并打印。

private static void test13() {List<Author> authors = getAuthors();Optional<Integer> maxScore = authors.stream().flatMap(author -> author.getBooks().stream()).map(book -> book.getScore()).max((o1, o2) -> o1 - o2);System.out.println("最大值:" + maxScore.get());Optional<Integer> min = authors.stream().flatMap(author -> author.getBooks().stream()).map(book -> book.getScore()).min((o1, o2) -> o1 - o2);System.out.println("最小值:" + min.get());
}
collect

把当前流转换成一个集合

例子:

获取一个存放所有作者姓名的List集合用**流.collect(Collectors.toList())**其中Collectors.中有很多方法

private static void test16() {List<Author> authors = getAuthors();List<String> collect = authors.stream().map(author -> author.getName()).collect(Collectors.toList());collect.forEach(System.out::println);
}

获取一个所有书名的Set集合

private static void test17() {List<Author> authors = getAuthors();Set<Book> collect = authors.stream().flatMap(author -> author.getBooks().stream()).distinct().collect(Collectors.toSet());System.out.println(collect);
}

获取一个map集合,map的kek为作者名,value为List

private static void test18() {//获取一个map集合,map的kek为作者名,value为List<Book>List<Author> authors = getAuthors();Map<String, List<Book>> collect = authors.stream().distinct().collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
}
查找和匹配
anyMatch

可以用来判断是否有任意符合匹配条件的元素,结果为boolean类型。

例子:

判断是否有年龄在29以上的作家

private static void test19() {List<Author> authors = getAuthors();System.out.println(authors.stream().anyMatch(author -> author.getAge() > 29));
}
allMatch

可以用来判断是否都符合匹配条件,结果为Boolean类型。如果都符合结果为true,否则结果为false。

例子:

判断是否所有作家都大于十岁

private static void test20() {List<Author> authors = getAuthors();System.out.println(authors.stream().allMatch(author -> author.getAge() > 10));
}
noneMatch

可以判断流中的元素是否都不符合匹配条件。如果都不符合结果为true,否则结果为false

findAny

获取流中的任意一个元素。该方法没有办法保证获取的一定是流中的第一个元素。

例子:

获取任意一个大于18的作家,如果存在就输出他的名字。

private static void test21() {List<Author> authors = getAuthors();Optional<Author> any = authors.stream().filter(author -> author.getAge() > 9).findAny();any.ifPresent(author -> System.out.println(author.getName()));
}
findFirst

获取流中的第一个元素。

例子:

获取一个年龄最小的作家,并输出他的姓名。

private static void test22() {List<Author> authors = getAuthors();Optional<Author> first = authors.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).findFirst();first.ifPresent(author -> System.out.println(author.getName()));
}
reduce归并

对流中的数据按照你指定的计算方式计算出一个结果

reduce的作用是把stream中的元素给组合起来,我们可以传入一个初始值,他会按照我们的计算方式依次拿流中的元素和初始值进行计算,计算结果再和后面的元素计算。

可以类比一下reduce两个参数重载形式:
在这里插入图片描述

例子:

求出所有作者年龄之和

private static void test23() {List<Author> authors = getAuthors();Integer sum = authors.stream().distinct().map(author -> author.getAge()).reduce(0, (result, element) -> result + element);System.out.println(sum);//62
}

使用reduce求年龄最大值

private static void test24() {List<Author> authors = getAuthors();Integer reduce = authors.stream().distinct().map(Author::getAge).reduce(Integer.MIN_VALUE, (result,element)->result>element?result:element);System.out.println(reduce);
}

使用reduce求年龄最小值

private static void test25() {List<Author> authors = getAuthors();Integer reduce = authors.stream().distinct().map(Author::getAge).reduce(Integer.MAX_VALUE, (result,element)->result<element?result:element);System.out.println(reduce);
}

reduce一个参数的重载形式(Optional reduce(BinaryOperator accumulator);)实际就是把流中第一个元素赋值给result,源代码:

boolean foundAny = false;
T result = null;
for (T element : this stream) {if (!foundAny) {foundAny = true;result = element;}elseresult = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();

用一个参数的reduce实现求年龄最小值:

private static void test26() {List<Author> authors = getAuthors();Optional<Integer> reduce = authors.stream().distinct().map(Author::getAge).reduce((integer, integer2) -> integer < integer2 ? integer:integer2);reduce.ifPresent(System.out::println);
}

2.5 注意事项

惰性求值:如果没有终结操作,中间操作是不会得到执行的。

流是一次性的:一旦一个流对象经过一个终结操作后,这个流就不能再被使用。

不会影响原数据:我们在流中可以多数据做很多处理。但是正常情况下是不会影响原来集合中的元素的。

三、Optional

4.1 概述

我们在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断。

尤其是对象中的属性还是个对象的情况下。这种判断会更多。
而过多的判断语句会让我们的代码显得臃肿不堪。
所以在JDK8中引入了Optional,养成使用Optional的习惯后你可以写出更优雅的代码来避免空指针异常
并且在很多函数式编程相关的API中也都用到了Optional,如果不会使用Optional也会对函数式编程的学习造成影响。

4.2 使用

4.2.1 创建对象

在这里插入图片描述

搭配**ifPresent()**消费数据

我还是想坚持我不轻易结束的原则,既然我们相遇了,就珍惜彼此。

四、函数式接口

5.1 概述

只有一个抽象方法的接口我们称之为函数接口。

JDK的函数式接口都加上了@functionalnterface 注解进行标识。但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式
接口。

五、方法引用

我们在使用lambda时,如果方法体中只有一个方法的调用的话(包括构造方法),我们可以用方法引用进一步简化代码。

6.1 推荐用法

我们在使用lambda时不需要考虑什么时候用方法引用,用哪种方法引用,方法引用的格式是什么。我们只需要在写完lambda方法发现方法体只有一行代码,并且是方法的调用时使用快捷键尝试是否能够转换成方法引用即可。当我们方法引用使用的多了慢慢的也可以直接写出方法引用。

6.2 基本格式

类名或者对象名::方法名

http://www.xdnf.cn/news/9922.html

相关文章:

  • 三套知识系统的实践比较:Notion、Confluence 与 Gitee Wiki
  • 关于 smali:2. 从 Java 到 Smali 的映射
  • 无需自建高防:APP遭遇DDoS的解决方案
  • CODEFORCES----1999A - A+B Again?
  • SQL进阶之旅 Day 7:视图与存储过程入门
  • vue的h函数(在 Vue 2中也称为 createElement)理解
  • SAP BASIS常用事务代码ST06 操作系统监控
  • UVa1384/LA3700 Interesting Yang Hui Triangle
  • OpenCv高阶(十九)——dlib关键点定位
  • 深度学习核心网络架构详解:从 CNN 到 LSTM
  • 关于DJI Cloud API Demo 终止维护公告-上云API源码停止维护
  • 文本预处理
  • 学习黑客小故事理解 Metasploit 的 Meterpreter
  • 【2025年电工杯数学建模竞赛A题】光伏电站发电功率日前预测问题+完整思路+paper+源码
  • BugKu Web渗透之备份是个好习惯
  • LeetCode Hot100(矩阵)
  • 逻辑回归知识点
  • stm32 + ads1292心率检测报警设置上下限
  • 鸿蒙分辨率
  • TDengine 运维——巡检工具(安装前检查)
  • 【Redis】第3节|深入理解Redis线程模型
  • 3.1.1栈的基本概念
  • 德国GEMÜ 3020特价型号3020 25D 7 1 4P002 3600
  • Java面试:从Spring Boot到分布式系统的技术探讨
  • VirtualBox安装 Rocky
  • AI绘画:手把手带你Stable Diffusion从入门到精通(系列教程)
  • window11系统 使用GO语言建立TDengine 连接
  • LLaMaFactory - 支持的模型和模板 常用命令
  • unordered_map与map之间的区别和联系
  • SpringBoot 日志