Stream流
# Stream创建
单列集合
Stream<Object> stream = list.stream();
1数组
Integer[] arr = {1,2,3,4,5}; Stream<Integer> stream = Arrays.stream(arr); Stream<Integer> stream2 = Stream.of(arr);
1
2
3双列集合
Map<String,Integer> map = new HashMap<>(); map.put("蜡笔小新",19); map.put("黑子",17); map.put("日向翔阳",16); Stream<Map.Entry<String,Integer>> stream = map.entrySet().stream();
1
2
3
4
5
# 中间操作
# 数据准备
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Author {
private Long id;
private String name;
private Integer age;
private String intro;
private List<Book> books;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Book {
private Long id;
private String name;
private String category;
private Integer score;
private String intro;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# filter
条件过滤,符合过滤条件的才能继续留在流中;
//打印所有姓名长度大于1的作家的姓名
List<Author> authors = getAuthors();
authors.stream()
.filter(author -> author.getName().length()>1)
.forEach(author -> System.out.println(author.getName()));
2
3
4
5
# map
对流中的元素进行计算或转换;
//所有作家年龄+10
authors.stream()
.map(author -> author.getAge())
.map(age->age+10)
.forEach(age-> System.out.println(age));
2
3
4
5
# distinct
去除流中的重复元素;
authors.stream()
.distinct()
.forEach(author -> System.out.println(author.getName()));
2
3
注意:distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以需要注意重写equals方法。
# sorted
//按照年龄降序排序
authors.stream()
.distinct()
.sorted((o1, o2) -> o2.getAge()-o1.getAge())
.forEach(author -> System.out.println(author.getAge()));
2
3
4
5
如果调用空参的sorted()方法,需要流中的元素是实现了Comparable;
# limit
//按年龄排序,打印年龄最大的两个人姓名
authors.stream()
.distinct()
.sorted()
.limit(2)
.forEach(author -> System.out.println(author.getName()));
2
3
4
5
6
# skip
//按年龄排序,打印除了最大年龄的其余作家姓名
authors.stream()
.distinct()
.sorted()
.skip(1)
.forEach(author -> System.out.println(author.getName()));
2
3
4
5
6
# flatMap
map只能把一个对象转换成另一个对象来作为流中的元素;
flatMap可以把一个对象转换成多个对象作为流中的元素;
//打印所有书籍名字,对重复元素进行去重
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book.getName()));
2
3
4
5
# 数学
max
数组中:
int max = Arrays.stream(nums).max().getAsInt();
1sum
数组中:
int sum = Arrays.stream(nums).sum();
1
# 终结操作
# collect
流转换为一个集合
//获取一个存放所有作者名字的List集合
List<String> nameList = authors.stream()
.map(author -> author.getName())
.collect(Collectors.toList());
//获取一个Map集合,map的key为作者名,value为List<Book>
Map<String, List<Book>> map = authors.stream()
.distinct()
.collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
2
3
4
5
6
7
8
# 查找与匹配
anyMatch
//判断是否有年龄在29以上的作家 boolean flag = authors.stream() .anyMatch(author -> author.getAge() > 29);
1
2
3allMatch
//判断是否所有的作家都是成年人 boolean flag = authors.stream() .allMatch(author -> author.getAge() >= 18);
1
2
3noneMatch
//判断作家是否都没有超过100岁的 boolean b = authors.stream() .noneMatch(author -> author.getAge() > 100);
1
2
3findAny
//获取任意一个年龄大于18的作家,如果存在就输出他的名字 Optional<Author> optionalAuthor = authors.stream() .filter(author -> author.getAge()>18) .findAny(); optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
1
2
3
4
5
6
# reduce归并
对流中的数据按照指定的计算方式计算出一个结果;
传入一个初始值,按照自定义的计算方式依次拿流中的元素和初始化值进行计算,计算结果再和后续的元素计算;
reduce两个参数的重载形式内部的计算方式如下:
T result = identity; for (T element : this stream) result = accumulator.apply(result, element) return result;
1
2
3
4其中 identity就是我们可以通过方法参数传入的初始值,accumulator的 apply具体进行什么计算也是我们通过方法参数来确定的;
//使用reduce求所有作者年龄的和
Integer sum = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(0, (result, element) -> result + element);
//使用reduce求所有作者中年龄的最大值
Integer max = authors.stream()
.map(author -> author.getAge())
.reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
2
3
4
5
6
7
8
9
10
# Optional
优雅得避免空指针异常;
# 创建对象
Optional的静态方法ofNullable来把数据封装成一个Optional对象;
Optional<Author> authorOptional = Optional.ofNullable(author);
# isPresent
会判断其内封装的数据是否为空,不为空时才会继续执行;
authorOptional.ifPresent(author -> System.out.println(author.getName()));
# 获取值
orElseGet
获取数据并且设置数据为空时的默认值;
如果数据不为空就能获取到该数据;
如果为空则根据你传入的参数来创建对象作为默认值返回;
Author author1 = authorOptional.orElseGet(() -> new Author());
1orElseThrow
获取数据,如果数据不为空就能获取到该数据;
如果为空则根据你传入的参数来创建异常抛出;
Optional<Author> authorOptional = Optional.ofNullable(getAuthor()); try { Author author = authorOptional.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("author为空")); System.out.println(author.getName()); } catch (Throwable throwable) { throwable.printStackTrace(); }
1
2
3
4
5
6
7
# 过滤
使用filter方法对数据进行过滤;
如果原本是有数据的,但是不符合判断,也会变成一个无数据的Optional对象;
authorOptional.filter(author -> author.getAge()>100).ifPresent(author -> System.out.println(author.getName()));
# 数据转换
map
Optional<List<Book>> optionalBooks = authorOptional.map(author -> author.getBooks());
optionalBooks.ifPresent(books -> System.out.println(books));
2
# 基本数据类型转换
大量的数据不断的重复装箱拆箱的时候,时间损耗不可忽视;
Stream有关得基本数据类型转换:
mapToInt,mapToLong,mapToDouble,flatMapToInt,flatMapToDouble等;
ArrayList<Integer> list = new ArrayList<>();
list.stream()
.mapToInt(x->x)
.toArray();
authors.stream()
.map(author -> author.getAge())
.map(age -> age + 10)
.filter(age->age>18)
.map(age->age+2)
.forEach(System.out::println);
2
3
4
5
6
7
8
9
10
11
12