Stream操作
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作
Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。
构造流的几种常见方法
// 1. Individual values Stream stream = Stream.of("a", "b", "c"); // 2. Arrays String [] strArray = new String[] {"a", "b", "c"}; stream = Stream.of(strArray); stream = Arrays.stream(strArray); // 3. Collections List<String> list = Arrays.asList(strArray); stream = list.stream(); |
需要注意的是,对于基本数值型,目前有三种对应的包装类型 Stream:
IntStream、LongStream、DoubleStream。当然我们也可以用 Stream<Integer>、Stream<Long> >、Stream<Double>,但是 boxing 和 unboxing 会很耗时,所以特别为这三种基本数值型提供了对应的Stream
数值流的构造
IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
IntStream.range(1, 3).forEach(System.out::println);
IntStream.rangeClosed(1, 3).forEach(System.out::println);
流转换为其它数据结构
// 1. Array
String[] strArray1 = stream.toArray(String[]::new);
// 2. Collection
List<String> list1 = stream.collect(Collectors.toList());
List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set set1 = stream.collect(Collectors.toSet());
Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
// 3. String
String str = stream.collect(Collectors.joining()).toString();
一个 Stream 只可以使用一次,上面的代码为了简洁而重复使用了数次。
流的操作
接下来,当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。
- Intermediate中间操作
- map:通过一个 Function 把一个元素类型为 T 的流转换成元素类型为 R 的流。
- flatMap:通过一个 Function 把一个元素类型为 T 的流中的每个元素转换成一个元素类型为 R 的流,再把这些转换之后的流合并。
- filter:过滤流中的元素,只保留满足由 Predicate 所指定的条件的元素。
- distinct:使用 equals 方法来删除流中的重复元素。
- limit:截断流使其最多只包含指定数量的元素。
- skip:返回一个新的流,并跳过原始流中的前 N 个元素。
- sorted:对流进行排序。
- peek:返回的流与原始流相同。当原始流中的元素被消费时,会首先调用 peek 方法中指定的 Consumer 实现对元素进行处理。
- dropWhile:从原始流起始位置开始删除满足指定 Predicate 的元素,直到遇到第一个不满足 Predicate 的元素。
- takeWhile:从原始流起始位置开始保留满足指定 Predicate 的元素,直到遇到第一个不满足 Predicate 的元素。
- Terminal终结操作:产生最终的结果
- forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
- .forEach 和 forEachOrdered 对流中的每个元素执行由 Consumer 给定的实现。在使用 forEach 时,并没有确定的处理元素的顺序;forEachOrdered 则按照流的相遇顺序来处理元素,如果流有确定的相遇顺序的话。
- reduce进行递归计算
- collect生成新的数据结构
- Short-circuiting
- anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
map
它的作用就是把 inputStream 的每一个元素,映射成 outputStream 的另外一个元素。
转换大写(把所有的单词转换为大写。):
List<String> output = wordList.stream().map(String::toUpperCase).collect(Collectors.toList());
转为平方数:
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
List<Integer> squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());
抽取对象中所有的id的集合
List<Long> idList = AList.stream.map(A::getId).collect(Collectors.toList());
flatMap
map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。还有一些场景,是一对多映射关系的,这时需要 flatMap。
Stream<List<Integer>> inputStream = Stream.of(
Arrays.asList(1),
Arrays.asList(2, 3),
Arrays.asList(4, 5, 6)
);
Stream<Integer> outputStream = inputStream.flatMap((childList) -> childList.stream());
filter
filter 对原始 Stream 进行某项测试,通过测试的元素被留下来生成一个新 Stream。
留下偶数
Integer[] sixNums = {1, 2, 3, 4, 5, 6};
Integer[] evens =Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new);
经过条件“被 2 整除”的 filter,剩下的数字为 {2, 4, 6}。
查找集合中的第一个对象
Optional<A> firstA= AList.stream() .filter(a -> "hanmeimei".equals(a.getUserName())) .findFirst();
获取符合指定条件的集合
List<A> firstA= AList.stream() .filter(a -> "hanmeimei".equals(a.getUserName())) .collect(Collectors.toList());
筛选+排序+取值成新的list
List<Integer> transactionsIds = transactions.parallelStream().
filter(t -> t.getType() == Transaction.GROCERY).
sorted(comparing(Transaction::getValue).reversed()).
map(Transaction::getId).
collect(toList());
filter筛选并修改
list.stream().filter(dto -> list2.contains(dto.getOrganId())).forEach(dto -> dto.setBillState(1));
其他总结
forEach配合流
list.forEach(accountCheckingSummaryByDayMapper::insert);
list.forEach(dto -> dto.setBillState(1));
list.forEach(dto -> dto.setBillState(dto.getBillState-1));
获取年龄最大的Person
Person maxAgePerson = personList.stream().max(Comparator.comparing(Person::getAge)).get();
list进行group变map
List<BusinessChannel> list =getList();
Map<String, List<BusinessChannel>> group = list.stream().collect(Collectors.groupingBy(BusinessChannel::getMchId));
list进行Collectors.toMap转为map
Map<Integer, Integer> projectOrerMap = fundInvestProjectOrders.stream().collect(Collectors.toMap(FundInvestProjectOrder::getProjectId, FundInvestProjectOrder::getOrder));
Map<Integer, FundInvestProjectOrder> projectOrerMap = fundInvestProjectOrders.stream().collect(Collectors.toMap(FundInvestProjectOrder::getProjectId, i -> i));
list对多个字段组合进行group
Map<String, List<OrganChannelPO>> channelMap =list.stream().collect(groupingBy(o -> o.getMchId() + "_" + o.getAppId()));
获取符合条件在集合中的数量
long count = list.stream().filter(s -> s.getSex().equals("女")).count();
获取集合中的元素id的集合
List<Long> idList = AList.stream.map(A::getId).collect(Collectors.toList());
获取id集合并去重
List<Long> idList = AList.stream.map(A::getId).distinct().collect(Collectors.toList());
对象去重
AlipayNotifyImage实体类,transactionId、imageId实体对象中的两个字段。以两个字段一起去重
List<AlipayNotifyImage> distinctClass = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getTransactionId() + ";" + o.getImageId()))), ArrayList::new));
以一个字段去重
list = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getImageId()))), ArrayList::new));
获取一个集合中重复元素
spaceCodeList是一个List<String>
Map<String, Long> collect = spaceCodeList.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
List<String> result = collect.entrySet().stream()
.filter(e -> e.getValue() > 1).map(Map.Entry::getKey)
.collect(Collectors.toList());
Function.identity()代表元素自身
list转换
List<CheckVO> voList = list.stream().map(po -> {
CheckVO vo=new CheckVO();
BeanUtils.copyProperties(po,vo);
return vo;
}).collect(Collectors.toList());
list元素排序
根据指定元素反排序
List<BillSummaryExcel> resultDetailExcelList = detailExcelList.stream().sorted(Comparator.comparing(BillSummaryExcel::getBillDate).reversed()).collect(Collectors.toList());
map的foreach遍历
myMap.forEach((k,v) -> {
System.out.println(k + ":" + v);
});