Stream流使用——(未完)
Stream介绍
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
Stream特性:
- 不是数据结构:它没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据。它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream,而不是从 source 删除那些元素。
- 不支持索引访问:但是很容易生成数组或者 List 。
- 惰性化:很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。Intermediate 操作永远是惰性化的。
- 并行能力。当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。
- 可以是无限的:集合有固定大小,Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。
- 注意事项:所有 Stream 的操作必须以 lambda 表达式为参数。
Stream 流操作类型:
- Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
- Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
1. 构造Stream流的方式
Stream stream = Stream.of("a", "b", "c");
String[] strArray = new String[] { "a", "b", "c" };
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
List<String> list = Arrays.asList(strArray);
stream = list.stream();
2. Stream流的之间的转换
注意:一个Stream流只可以使用一次,这段代码为了简洁而重复使用了数次,因此会抛出 stream has already been operated upon or closed 异常。
Stream<String> stream2 = Stream.of("a", "b", "c");
// 转换成 Array
String[] strArray1 = stream2.toArray(String[]::new);
// 转换成 Collection
List<String> list1 = stream2.collect(Collectors.toList());
List<String> list2 = stream2.collect(Collectors.toCollection(ArrayList::new));
Set set1 = stream2.collect(Collectors.toSet());
Stack stack1 = stream2.collect(Collectors.toCollection(Stack::new));
// 转换成 String
String str = stream.collect(Collectors.joining()).toString();
3. Stream流的排序
a. Stream流的实体操作
//实体根据年龄 倒序
List<User> collect1 = users.stream().sorted(Comparator.comparing(User::getName).reversed()).collect(Collectors.toList());
//实体根据年龄 正序
List<User> collect2 = users.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
b. Stream流的直接操作
//直接排序 倒序
List<Integer> collect3 = list.stream().sorted(Comparator.comparing(Integer::intValue).reversed()).collect(Collectors.toList());
//直接排序 正序
List<Integer> collect4 = list.stream().sorted().collect(Collectors.toList());
List<Integer> collect5 = list.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList());
4. Stream流的limit使用
limit 方法用于获取指定数量的流。
//Stream流的limit使用
List<User> collect6 = users.stream().limit(2).collect(Collectors.toList());
List<Integer> collect7 = list.stream().limit(2).collect(Collectors.toList());
5. Stream流的skip使用
skip方法用于从前面扔掉指定数量的流。
//扔掉前n条数据
List<User> collect8 = users.stream().skip(3).collect(Collectors.toList());
List<Integer> collect9 = list.stream().skip(3).collect(Collectors.toList());
6. Steam流进行过滤
List<User> collect10 = users.stream().filter(user -> "王五".equals(user.getName())).collect(Collectors.toList());
List<Integer> collect11 = list.stream().filter(val -> val != 4).collect(Collectors.toList());
7. Stream流的map使用
map方法用于映射每个元素到对应的结果,一对一。
//修改当前值
List<User> collect12 = users.stream().map(e ->{
if (e.getAge() == 18) {
e.setAge(999);
}
return e;
}).collect(Collectors.toList());
//赋值新的实体
List<UserTwo> collect13 = users.stream().map(e -> {
UserTwo userTwo = new UserTwo();
BeanUtils.copyProperties(e, userTwo);
return userTwo;
}).collect(Collectors.toList());
List<Integer> collect14 = list.stream().map(e -> e * e).collect(Collectors.toList());
8. Stream流的分组使用
Map<Integer, List<User>> collect15 = users.stream().collect(Collectors.groupingBy(User::getAge));
Map<Integer, List<Integer>> collect16 = list.stream().collect(Collectors.groupingBy(Integer::intValue));
9. Stream流的根据实体去重
//业务需要去重的代码
List<User> collect= userList.stream().filter(distinctByKey1(s -> s.getBizUserId())).collect(Collectors.toList());
//必要的
static <T> Predicate<T> distinctByKey1(Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}