java8函数式编程-Stream流简介绍
2.1、概述
java8的Stream使用的是函数式编程模式,它可以被用来对集合或数组进行链状流失的操作,可以方便的让我们对集合或数组操作
2.2、案例数据准备
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode // 用于后期的去重
public class Book {
private Long id;
private String name;
private String category;
private Integer score;
private String intro;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode // 用于后期的去重
public class Author {
private Long id;
private String name;
private Integer age;
private String intro;
private List<Book> books;
}
private static List<Author> getAuthors() {
// 数据初始化
Author author = new Author(1L,"蒙多",33,"拿着菜刀的祖安人",null);
Author author2 = new Author(2L,"亚索",33,"拿着无鞘之刃的剑客",null);
Author author3 = new Author(3L,"大头",33,"头很大的约德尔人",null);
Author author4 = new Author(4L,"德莱厄斯",33,"拿着斧头的诺克萨斯人",null);
// 书籍列表
List<Book> books1 = new ArrayList<>();
List<Book> books2 = new ArrayList<>();
List<Book> books3 = new ArrayList<>();
books1.add(new Book(1L,"books1的名字","books1的标签",88,"books1的简介"));
books1.add(new Book(2L,"books2的名字","books2的标签",89,"books1的简介"));
books2.add(new Book(3L,"books3的名字","books3的标签",90,"books2的简介"));
books2.add(new Book(3L,"books4的名字","books4的标签",91,"books2的简介"));
books2.add(new Book(4L,"books5的名字","books5的标签",92,"books2的简介"));
books3.add(new Book(5L, "books6的名字", "books7的标签", 93, "books3的简介"));
books3.add(new Book(6L, "books7的名字", "books7的标签", 94, "books3的简介"));
books3.add(new Book(6L, "books7的名字", "books7的标签", 94, "books3的简介"));
author.setBooks(books1);
author2.setBooks(books2);
author3.setBooks(books3);
author4.setBooks(books3);
List<Author> authorList = new ArrayList<Author>(Arrays.asList(author,author2,author3,author4));
return authorList;
}
2.3、快速入门
2.3.1、需求
我们可以调用getAuthors方法获取到作家的集合,现在需要打印所有年纪小于18 的作家的名字,并且要注意去重
2.3.2、实现
List<Author> authors = getAuthors();
authors.stream() // 将集合转换为流
.distinct() // 去重
.filter(author -> author.getAge() < 18) // 过滤
.forEach(author -> System.out.println(author.getName()));
2.4、常用操作
2.4.1、创建流
- 单列集合
- 集合对象.stream
List<Author> authors = getAuthors();
Stream<Author> stream = authores.stream();
- 数组
- Arrays.stream(数组)或者使用Stream.of来创建
Integer[] arr = {1,2,3,4}
Stream<Integer> stream = Arrats.stream(arr);
Stream<Integer> stream2 = Stream.of(arr);
- 双列集合
- 转为单列集合之后再创建
Map<String,Integer> map = new HashMap<>();
map.put("张三",19);
map.put("李四",18);
map.put("王五",17);
Stream<Map.Entry<String,Inter>> stream = map.entrySet().stream();
2.4.2、中间操作
-
**fliter:**可以对流中的元素进行条件过滤
-
map:
可以把对流中的元素进行计算或转换
例如,打印所有作家姓名
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getName())
.forEach(name -> System.out.println(name));
-
distinct:可以去除流中的重复元素
-
sorted
可以对流中的元素进行排序
例如,对流中的元素按照年龄进行降序排序,并且不能有重复元素
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted(Comparator.comparingInt(Author::getAge))
.forEach(name -> System.out.println(name.getAge()));
-
limit:设置流的最大长度,超出的部分将被抛弃
-
skip:跳过流中的前n个元素,返回剩下的元素
-
flapMap
map只能将一个对象转化为另一个对象俩作为流中的元素。而flatMap可以吧一个对象转为多个对象作为流中的元素
例一:
打印所有书籍的名字,去重
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(System.out::println);
例二:
打印数据的所有分类,对分类进行去重,不能出现这种格式:哲学、爱情
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.flatMap(book -> Arrays.stream(book.getCategory().split("、")))
.distinct()
.forEach(System.out::println);
2.4.3、终结操作
-
foreach:对流中的元素进行遍历操作,通过传入的参数指定对遍历的元素进行什么具体操作
-
count:获取当前流中元素的个数
-
max&min:可以用来获取流中的最值
Optional<Book> max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.max(Comparator.comparingInt(Book::getScore));
System.out.println(max.get());
- collect:将流转化为一个集合
List<String> collect = authors.stream()
.map(author -> author.getName())
.collect(Collectors.toList());
System.out.println(collect);
- 查找与匹配
- anyMatch:用来判断是否偶遇任意符合匹配条件的元素,结果为boolean类型
- allMatch用来判断是否都符合判断条件,结果为boolean类型
- noneMatch:用来判断流中的元素是否都不符合判断条件,结果为boolean类型
boolean b = authors.stream()
.allMatch(author -> author.getAge() >= 18);
System.out.println(b);
- **findAny**:获取流中的任意一个元素。该方法没有办法保证获取的一定是流中的第一个元素。
- **findFirst**:获取流中的第一个元素
2.4.4、reduce归并(终结操作)
对流中的数据按照指定的计算方式计算出一个结果( 缩减操作 )
reduce的作用是把stream中的元素给组合气啦,我们可以传入一个初始值,她会按照我们的计算方法一次拿流中的元素和在初始化值的基础上进行计算,计算机结果再和后面的元素计算
内部计算方式如下:
T result = identity;
for(T element : thie stream)
result = accumulator.apply(result, element)
return result
其中identity就是我们可以通过方法参数传入的初始值,accumulator的apply具体通过什么计算也是根据参数来确定的
例子:
使用reduce计算所有作者的年龄总和
Integer sum = authors.stream()
.map(Author::getAge)
.distinct()
.reduce(0, (result, element) -> result + element);
System.out.println(sum);
例子:
求所有作者中年龄的最大值
Integer max = authors.stream()
.map(Author::getAge)
.reduce(Integer.MIN_VALUE, (res, ele) -> res < ele ? ele : res);
System.out.println(max);
reduce一个参数的重载形式内部计算:
boolean foundAny = false;
T result = null;
// 拿到第一个元素作为初始化值,之后跟后续元素进行计算
for (T element : this stream){
if(!foundAny){
founAny = true;
result = element;
}
ele
result = accumulator.apply(result, element)
}
return foundany ? Optionaal.of(result) : Optional.empty();
2.5、注意事项
- 惰性求值(如果没有终结操作,中间操作是不会执行的)
- 流是一次性的(一旦一个流对象经过一个终结操作后,这个流就不能再被使用)
- 不会影响原数据(我们在流中可以多数据做很多处理。打哪书正常情况下是不会影响原来集合中的元素的)

浙公网安备 33010602011771号