Stream流
- 一.概述
- 二.数据准备
- 二.Stream流的创建
- 2.1 单列集合创建Stream流.
- 2.2 数组创建Stream流
- 2.3 双列集合创建Stream流
- 三. 中间操作.
- 3.1 filter(过滤操作)
- 3.2 map(计算或者转换)
- 3.3 distinct(去重操作)
- 3.4 sorted(排序操作)
- 3.5 limit (设置流的长度)
- 3.6 skip(跳过前n个元素)
- 3.7 flatMap(一个对象转为多个对象)
- 四.终结操作
- 4.1 forEach(遍历流中的每一个元素)
- 4.2 count(获取流中元素的个数)
- 4.3 max和min(获取流中的最大值或最小值)
- 4.4 collection(把当前流转化为一个集合) ==最常用==
- 4.5 anyMatch(任一匹配)
- 4.6 allMatch(都符合条件)
- 4.7 noneMatch(都不符合条件)
- 4.8 findAny(获取任意一个元素)
- 4.9 findFirst(获取流中的第一个元素)
一.概述
- 在 Java 中,Stream 是一个来自
java.util.stream
包的接口,用于对集合(如List、Set等)或数组等数据源进行操作的一种抽象层。它可以让你以一种声明式的方式处理数据,更专注于 “做什么” 而不是 “怎么做”。简单来说,Stream
就像是一条数据的管道,数据在这个管道中流动,并且可以在流动的过程中被各种操作修改。 - 对Stream流的操作可以分为三种:
- 创建流: 可以由数组或者集合创建.
- 中间操作: 每次返回一个新的流,可以有多个中间操作
- 终结操作: 每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合.
- Stream流的特性:
- 惰性求值(Lazy Evaluation):
Stream
流的中间操作(如filter、map、sorted
等)是惰性求值的。这意味着当你定义了一系列中间操作时,这些操作并不会立即执行。只有当遇到终端操作(如forEach、reduce、collect
等)时,整个操作链才会被触发执行。 - 不可变(Immutability): Stream 本身是不可变的。这意味着一旦一个 Stream 对象被创建,你不能修改它。每一个中间操作都会返回一个新的 Stream 对象,而不是在原始的 Stream 上进行修改。
- 管道化(Pipelining): Stream 操作可以像管道一样串联起来。一个操作的输出可以作为下一个操作的输入,从而可以对数据进行连续的处理。这种管道化的方式使得代码更加紧凑和易读,并且能够高效地处理数据。
- 内部迭代(Internal Iteration): 与传统的外部迭代(如使用for循环)不同,
Stream
采用内部迭代。在传统的外部迭代中,你需要手动控制迭代的过程,例如,在一个for循环中,你要明确地指定循环的起始、结束条件和每次迭代的步长。而在Stream
中,迭代的过程是由Stream
库内部管理的,你只需要指定要对数据进行什么操作(通过中间操作和终端操作)。 - 支持多种数据源和数据类型:
- 数据源多样性:Stream 可以从各种数据源创建,如集合(
List、Set、Map
等)、数组、I/O 通道等。这使得它可以广泛地应用于不同的数据处理场景。 - 数据类型多样性:它可以处理各种数据类型,包括基本数据类型(通过
IntStream、LongStream、DoubleStream
等专门的流)和引用数据类型。例如,可以创建一个IntStream
来处理整数数组,也可以创建一个Stream<String>
来处理字符串列表。
- 数据源多样性:Stream 可以从各种数据源创建,如集合(
- 惰性求值(Lazy Evaluation):
二.数据准备
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Author {//idprivate Long id;//姓名private String name;//年龄private Integer age;//简介private String intro;//作品private List<Book> books;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Book {//idprivate Long id;//书名private String name;//分类private String category;//评分private Integer score;//简介private String intro;}
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);Author 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);List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));return authorList;}
二.Stream流的创建
2.1 单列集合创建Stream流.
List<Author> authors = getAuthors();Stream<Author> stream = authors.stream();
2.2 数组创建Stream流
Arrays.stream(数组)
或者使用Stream.of
来创建
Integer[] arr = {1,2,3,4,5};Stream<Integer> stream = Arrays.stream(arr);Stream<Integer> stream2 = Stream.of(arr);
2.3 双列集合创建Stream流
- 转换成单列集合后再创建
Map<String,Integer> map = new HashMap<>();map.put("蜡笔小新",19);map.put("黑子",17);map.put("日向翔阳",16);Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
三. 中间操作.
3.1 filter(过滤操作)
- 可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中。
- 打印所有姓名长度大于1的作家的姓名.
List<Author> authors = getAuthors();authors.stream().filter(author -> author.getName().length()>1).forEach(author -> System.out.println(author.getName()));
3.2 map(计算或者转换)
打印所有作家的姓名
List<Author> authors = getAuthors();authors.stream().map(author -> author.getName()).forEach(name->System.out.println(name));
3.3 distinct(去重操作)
- 打印所有作家的姓名,并且要求其中不能有重复元素。
List<Author> authors = getAuthors();authors.stream().distinct().forEach(author -> System.out.println(author.getName()));
注意:distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以需要注意重写equals方法。
3.4 sorted(排序操作)
- 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素。
List<Author> authors = getAuthors();// 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素。authors.stream().distinct().sorted((o1, o2) -> o2.getAge()-o1.getAge()).forEach(author -> System.out.println(author.getAge()));
3.5 limit (设置流的长度)
- 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名。
List<Author> authors = getAuthors();authors.stream().distinct().sorted().limit(2).forEach(author -> System.out.println(author.getName()));
3.6 skip(跳过前n个元素)
- 打印除了年龄最大的作家外的其他作家,要求不能有重复元素,并且按照年龄降序排序。
//打印除了年龄最大的作家外的其他作家,要求不能有重复元素,并且按照年龄降序排序。List<Author> authors = getAuthors();authors.stream().distinct().sorted().skip(1).forEach(author -> System.out.println(author.getName()));
3.7 flatMap(一个对象转为多个对象)
- 打印所有书籍的名字。要求对重复的元素进行去重。
// 打印所有书籍的名字。要求对重复的元素进行去重。List<Author> authors = getAuthors();authors.stream().flatMap(author -> author.getBooks().stream()).distinct().forEach(book -> System.out.println(book.getName()));
四.终结操作
4.1 forEach(遍历流中的每一个元素)
- 输出所有作家的名字
// 输出所有作家的名字List<Author> authors = getAuthors();authors.stream().map(author -> author.getName()).distinct().forEach(name-> System.out.println(name));
4.2 count(获取流中元素的个数)
- 打印这些作家的所出书籍的数目,注意删除重复元素。
//打印这些作家的所出书籍的数目,注意删除重复元素。List<Author> authors = getAuthors();long count = authors.stream().flatMap(author -> author.getBooks().stream()).distinct().count();System.out.println(count);
4.3 max和min(获取流中的最大值或最小值)
- 分别获取这些作家的所出书籍的最高分和最低分并打印。
// 分别获取这些作家的所出书籍的最高分和最低分并打印。//Stream<Author> -> Stream<Book> ->Stream<Integer> ->求值List<Author> authors = getAuthors();Optional<Integer> max = authors.stream().flatMap(author -> author.getBooks().stream()).map(book -> book.getScore()).max((score1, score2) -> score1 - score2);Optional<Integer> min = authors.stream().flatMap(author -> author.getBooks().stream()).map(book -> book.getScore()).min((score1, score2) -> score1 - score2);System.out.println(max.get());System.out.println(min.get());
4.4 collection(把当前流转化为一个集合) 最常用
- 获取一个存放所有作者名字的List集合。
// 获取一个存放所有作者名字的List集合。List<Author> authors = getAuthors();List<String> nameList = authors.stream().map(author -> author.getName()).collect(Collectors.toList());System.out.println(nameList);
- 获取一个所有书名的Set集合。
// 获取一个所有书名的Set集合。List<Author> authors = getAuthors();Set<Book> books = authors.stream().flatMap(author -> author.getBooks().stream()).collect(Collectors.toSet());System.out.println(books);
- 获取一个Map集合,map的key为作者名,value为List
// 获取一个Map集合,map的key为作者名,value为List<Book>List<Author> authors = getAuthors();Map<String, List<Book>> map = authors.stream().distinct().collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));System.out.println(map);
4.5 anyMatch(任一匹配)
- 判断是否有年龄在29以上的作家
// 判断是否有年龄在29以上的作家List<Author> authors = getAuthors();boolean flag = authors.stream().anyMatch(author -> author.getAge() > 29);System.out.println(flag);
4.6 allMatch(都符合条件)
- 判断是否所有的作家都是成年人
// 判断是否所有的作家都是成年人List<Author> authors = getAuthors();boolean flag = authors.stream().allMatch(author -> author.getAge() >= 18);System.out.println(flag);
4.7 noneMatch(都不符合条件)
- 判断作家是否都没有超过100岁的。
// 判断作家是否都没有超过100岁的。List<Author> authors = getAuthors();boolean b = authors.stream().noneMatch(author -> author.getAge() > 100);System.out.println(b);
4.8 findAny(获取任意一个元素)
- 获取任意一个年龄大于18的作家,如果存在就输出他的名字
// 获取任意一个年龄大于18的作家,如果存在就输出他的名字List<Author> authors = getAuthors();Optional<Author> optionalAuthor = authors.stream().filter(author -> author.getAge()>18).findAny();optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
4.9 findFirst(获取流中的第一个元素)
- 获取流中的第一个元素。
// 获取一个年龄最小的作家,并输出他的姓名。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()));