JDK8新特性——流(Stream)
Stream是什么?
Stream是Java8中新加入的api,更准确的说:
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作 。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性.
Stream特性
- 不存储数据
- 不改变与数据
- 延迟执行
Stream优点
- 简化代码
- 使用并行流可以利用多核特性,提升效率
Stream操作
stream上的所有操作分为两类:中间操作和结束操作,中间操作只是一种标记,只有结束操作才会触发实际计算。
常用api操作如下
中间操作
方法 | 介绍 |
---|---|
filter | 过滤流,过滤流中的元素,返回一个符合条件的Stream |
map | 转换流,将一种类型的流转换为另外一种流。(mapToInt、mapToLong、mapToDouble 返回int、long、double基本类型对应的Stream) |
flatMap | 一个或多个流合并成一个新流。(flatMapToInt、flatMapToLong、flatMapToDouble 返回对应的IntStream、LongStream、DoubleStream流) |
distinct | 返回去重的Stream |
sorted | 返回一个排序的Stream |
peek | 主要用来查看流中元素的数据状态 |
limit | 返回前n个元素数据组成的Stream。属于短路操作 |
skip | 返回第n个元素后面数据组成的Stream |
结束操作
方法 | 介绍 |
---|---|
forEach | 循环操作Stream中数据 |
toArray | 返回流中元素对应的数组对象 |
reduce | 聚合操作,用来做统计 |
collect | 聚合操作,封装目标数据 |
min、max、count | 聚合操作,最小值,最大值,总数量 |
anyMatch | 短路操作,有一个符合条件返回true |
allMatch/noneMatch | 所有数据都符合条件返回true/所有数据都不符合条件返回true。 |
findFirst/findAny | 短路操作,获取第一个元素/短路操作,获取任一元素 |
forEachOrdered | 暗元素顺序执行循环操作 |
管道Stream使用示例
Stream的获取
-
通过集合Collection获取
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); Stream<Integer> stream = list.stream();
-
通过数组获取
String[] array = {"are", "you", "ok"}; Stream<String> stream = Arrays.stream(array); //对于基本类型数组的处理 int[] array = {1, 2, 3, 4, 5}; Stream<Integer> stream = Arrays.stream(array).boxed(); //Arrays.stream(array)获取的是一个IntStream对象,boxed 方法用于将目前 Stream 中的基本类型装箱
-
直接通过值获取
Stream<String> stream = Stream.of("are", "you", "ok");
Stream常用管道操作
-
筛选
filter
filter函数接收一个Lambda表达式作为参数,该表达式返回 boolean,在执行过程中,流将元素逐一输送给filter,并筛选出执行结果为 true 的元素;
//筛选出列表中的非空项 List<String> list = Arrays.asList("are", "you", "", "ok"); List<String> filted = list.stream() .filter(x -> !x.isEmpty()) .collect(Collectors.toList());
-
去重
diatinct
//去除列表中的重复元素 List<String> list = Arrays.asList("are", "you", "you", "ok"); List<String> distincted = list.stream() .distinct() .collect(Collectors.toList());
-
截取l
imit
截取流的前N个元素
//获取Stream的前3个值 List<String> list = Arrays.asList("are", "you", "fucking", "ok"); List<String> distincted = list.stream() .limit(3) .collect(Collectors.toList());
-
跳过
skip
跳过流的前n个元素
List<String> list = Arrays.asList("are", "you", "fucking", "ok"); List<String> distincted = list.stream() .skip(2) .collect(Collectors.toList());
-
映射
map
对流中的每个元素执行一个函数,使得元素转换成另一种类型输出。流会将每一个元素输送给map函数,并执行map中的Lambda表达式,最后将执行结果存入一个新的流中。
如:将 list 中每一个 Integer类型元素自增后转化为 String类型。//将集合中的每一个元素+1,并转为字符串 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); List<String> result = list.stream() .map(x -> String.valueOf(++x)) .collect(Collectors.toList());
-
合并多个流
flatMap
List<String> list1 = ..... List<String> list2 = ... List<List<String>> list = Arrays.asList(list1,list2); //将list中的list1,list2合并为一个List<String> List<String> listsum = list.stream() .flatMap(List::stream) .collect(Collectors.toList());
以下一个实际的应用例子:列出 list 中各不相同的单词;
List<String> list = new ArrayList<String>(); list.add("I am a boy"); list.add("Variety is the spice of life"); list.add("There is no royal road to learning"); list.stream().map(line -> line.split(" ")) //将每一个项分词,并映射为数组 .flatMap(Arrays::stream) //将每一个分项数组组合并到主流中,形成一个包含所有分项数组的 //总数组流 .distinct() //去重 .forEach(System.out::println); //打印
-
匹配元素
anyMatch
、allMatch
-
是否匹配任意元素
antMatch
anyMatch用于判断流中是否存在至少一个元素满足指定的条件,这个判断条件通过Lambda表达式传递给anyMatch,执行结果为boolean类型。
//判断流中是否含有>10的项 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6); boolean result = list.stream() .anyMatch(x -> x > 10);
-
是否匹配所有元素
allMatch
allMatch用于判断流中的所有元素是否都满足指定条件,这个判断条件通过Lambda表达式传递给anyMatch,执行结果为boolean类型。
//判断流中是否全部>5 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6); boolean result = list.stream().allMatch(x -> x > 5);
-
是否未匹配所有元素
noneMatch
noneMatch与allMatch恰恰相反,它用于判断流中的所有元素是否都不满足指定条件:
//判断流中是否 全部不满足 >5 List<Integer> list = Arrays.asList(1,2,3,4,5,6); boolean result = list.stream() .noneMatch(x->x>5);
-
获取元素
- 获取任意元素
findAny
findAny从流中随机选出 一个元素出来,它返回一个Optional类型的元素。
List<Integer> list = Arrays.asList(1,2,3,4,5,6); Optional<Integer> result = list.stream().findAny(); if(result.isPresent()){ Integer randValue = result.get(); } //or: Integer randValue1 = result.orElse(0); //合并的调用方式 Integer randValue2 = list.stream().findAny().orElse(0);
- 获取第一个元素
findFirst
Optional<Integer> result = list.stream().findFirst();
- 获取任意元素
-
归约
归约是将集合中的所有元素经过指定运算,折叠成一个元素输出,如:求最值、平均数等,这些操作都是将一个集合的元素折叠成一个元素输出;
//获取一个整型列表的最大值,最小值 Random random = new Random(); List<Integer> list = random.ints(1, 100).limit(50).boxed().collect(Collectors.toCollection(ArrayList::new)); int max = list.stream().max(Integer::compare).orElse(-1); //获取最大值 int min = list.stream().min(Integer::compare).orElse(-1); //获取最小值 System.out.println(max); System.out.println(min); //使用基于数据流的方式,将流装载相应的 SummaryStatistics 来进行归约计算,可以实现更多的操作; IntSummaryStatistics stats = list.stream().mapToInt(x -> x).summaryStatistics(); int max1 = stats.getMax(); //获取最大值 int min1 = stats.getMin(); //获取最小值 double sum = stats.getSum(); //获取总值 double avg = stats.getAverage(); //获取平均值 long count = stats.getCount(); //获取总数量 List<? extends Number> numbers = Arrays.asList(max1, min1, sum, avg, count); numbers.forEach(System.out::println);
-
遍历流
forEach
据流提供了新的forEach方法遍历该流中的每个元素,方法参数为一个Lambda表达式,用于对每一个遍历的元素执行的操作;
//输出10个随机数 Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
-
排序
sorted
sorted方法用来流排序,默认升序排布,可以使用一个 Comparator 作为参数来实现自定义排序;
//输出10个排序好的随机数 Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println); //升序 random.ints().limit(10).sorted(x1,x2 -> Integer.compare(x2, x1)).forEach(System.out::println); //降序
Stream转换为Collection、Array、String
Stream 可以通过 Collector 收集器,将其转化为 Array,Collection,Map,String;
-
Stream->数组
//普通转换 Stream<String> stream = Stream.of("are","you","ok"); String[] array = stream().toArray(); //涉及拆箱、装箱操作的转换 Stream<Integer> stream = Stream.of(1,2,3,4,5,6); int[] array = stream.mapToInt(x->x).toArray(); Integer[] array = stream.toArray(Integer[]::new); //将 List<Inetegr> 转化为 String[] List<Integer> list = Arrays.asList(1,2,3,4,5); String[] array = list.stream().map(String::valueOf).toArray(String[]::new);
-
Stream -> List
List<Integer> list1 = stream.collect(Collectors.toList()); List<Integer> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
-
Stream ->Set
Set<Integer> set = stream.collect(Collectors.toCollection(Set::new));
-
Stream ->Stack
Stack<Integer> stack = stream.collect(Collectors.toCollection(Stack::new));
-
Stream ->Map
Map<Integer, String> map = Stream.of("are","you","ok").collect(Collectors.toMap( s -> s.hashCode(), s -> s));
-
tream -> String
Stream 可以很方便转化为 String,利用这一个特性,可以十分方便地将一个 Collection(List,Set等)转化为使用某个标点符号分隔的字符串;
//将 List 转化为使用 “,” 分隔的字符串 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7); String str = list.stream().map(x->x.toString()).collect(Collectors.joining(",")); System.out.println(str); //输出: 1,2,3,4,5,6,7
对Map使用Stream
虽然 JDK8 的 Stream API 不直接支持 Map,但是我们可以通过对 Map 的 entrySet,keySet,valueColletion 生成 Stream 来进行曲线救国,如下示例:
Map<Integer,String> map = new HashMap<Integer,String>(){{
put(1,"are");
put(2,"you");
put(3,"ok"); }};
map.entrySet().forEach(System.out::println); //遍历key-value
int randomKey = map.keySet().stream().findAny().orElse(-1); //随机取出一个key
String values = map.values().stream().distinct().collect(Collectors.joining(",")); //将value去重后组装成使用“,”分隔的字符串
Q.E.D.
Comments | 0 条评论