Stream简介
Java8 Stream流使用的是函数式编程模式,和Spark的RDD编程模型类似,可以将Stream流中的各种操作类比为Spark中的算子,Stream流的操作可以分为中间操作(Spark中的Transform操作)和终止操作(Spark中的Action操作)
- 中间操作会再返回一个流,因此中间可以链接多个中间操作
- 无状态:指元素的处理不受前面元素的影响,例如filter,map等
- 有状态:有状态的中间操作必须等到所有元素处理之后才知道最终结果,例如distinct,sorted等
- 终止操作是对流操作的一个结束动作,返回void或者非流结果
- 短路操作:指不用处理全部元素就可以返回全部结果,例如anyMatch,findFirst等
- 非短路操作:必须处理所有元素才能得到最终结果,例如forEach,reduce等
Stream流只有在遇到终端操作时,才会正在触发流的计算,即计算具体延迟性,和Spark的懒加载类似。
Stream流操作
创建Stream流
有三种常用的创建Stream的方法:
- Collection 集合使用stream()创建串行流,使用parallelStream创建并行流
List<String> list = new ArrayList<>();
Stream<String> listStream = list.stream();
Stream<String> listParallelStream = list.parallelStream();
复制代码
- Arrays中的静态方法stream() 获取数据流,接收参数为数组类型
String[] strArray = new String[10];
Stream<String> strStream = Arrays.stream(strArray);
复制代码
- 使用Stream类中的静态方法of()创建数据流
Stream<String> ofStream = Stream.of("1", "2", "3");
复制代码
Stream常用操作
- filter: 根据指定条件做过滤,返回符合条件的流
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
Stream<Integer> result = integerStream.filter(x -> x > 5);
复制代码
- map: 将流中每个元素执行map中的逻辑方法,返回执行执行完逻辑之后的流
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
Stream<Integer> result = integerStream.map(x -> x*2);
复制代码
- mapToInt mapToLong mapToDouble mapToObj: 有
InteStream
,LongStream
,DoubleStream
三个原始类型流,mapToInt
,mapToLong
,mapToDouble
可以将对象流分别转换为对应的原始类型流,mapToObj
可以将原始类型流转为对象流
Stream<String> strStream = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
IntStream intStream = strStream.mapToInt(Integer::parseInt);
LongStream longStream = strStream.mapToLong(Long::parseLong);
DoubleStream doubleStream = strStream.mapToDouble(Double::parseDouble);
Stream<String> objStream = intStream.mapToObj(x -> "obj_" + x);
复制代码
- distinct:对流中元素去重,使用
equal()
方法判断元素是否相等,返回去重之后的流
Stream<String> strStream = Stream.of("1", "1", "1", "1", "1", "1", "7", "8", "9");
Stream<String> result = strStream.distinct();
复制代码
- sorted:有一个无参方法和一个有参方法,无参方法要求Stream中元素必须实现了
Comparable
接口,有参方法sorted(Comparator<? super T> comparator)
不需要元素实现Comparable
接口,通过指定的元素比较器对流内的元素进行排序
// 输出1 2 3 4 5 6 7 8 9
Stream<String> strStream1 = Stream.of("9", "8", "7", "6", "5", "4", "3", "2", "1");
strStream1.sorted().forEach(x -> System.out.print(x+" "));
// 输出9 8 7 6 5 4 3 2 1
Stream<String> strStream2 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
strStream2.sorted((s1, s2) -> {
return s2.compareTo(s1);
}).forEach(x -> System.out.print(x+" "));
复制代码
- limit(long maxSize):对流进行截取,最多保留maxSize个元素,返回截取后的流
Stream<String> strStream = Stream.of("1", "1", "1", "1", "1", "1", "7", "8", "9");
Stream<String> result = strStream.limit(5);
复制代码
- skip(long num):跳过前num个元素,如果流中元素不足num个,则返回一个空流
Stream<String> strStream = Stream.of("1", "1", "1", "1", "1", "1", "7", "8", "9");
Stream<String> result = strStream.skip(5);
复制代码
- forEach:类似于for循环,可支持多线程遍历,但不保证顺序
// 输出9 8 7 6 5 4 3 2 1
Stream<String> strStream1 = Stream.of("9", "8", "7", "6", "5", "4", "3", "2", "1");
strStream1.forEach(x -> System.out.print(x+" "));
// 输出顺序不固定
Stream<String> strStream2 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
strStream2.parallel().forEach(x -> System.out.print(x+" "));
复制代码
- forEachOrdered:该方法可以保证顺序遍历
// 输出9 8 7 6 5 4 3 2 1
Stream<String> strStream1 = Stream.of("9", "8", "7", "6", "5", "4", "3", "2", "1");
strStream1.forEachOrdered(x -> System.out.print(x+" "));
// 输出1 2 3 4 5 6 7 8 9
Stream<String> strStream2 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
strStream2.parallel().forEachOrdered(x -> System.out.print(x+" "));
复制代码
- toArray:有一个无参方法和一个有参方法,无参方法将流中的元素转换为
Object
数组,有参方法toArray(IntFunction<A[]> generator)
可将流中元素转换为指定类型的元素数组
Stream<String> strStream1 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
Object[] objArray = strStream1.toArray();
Stream<String> strStream2 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
String[] strArray = strStream2.toArray(String[]::new);
复制代码
- min max count:主要对流中的元素进行统计,其中
min
和max
返回Opetion
对象
Stream<String> strStream1 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
Optional<String> min = strStream1.min(String::compareTo);
Stream<String> strStream2 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
Optional<String> max = strStream2.max(String::compareTo);
Stream<String> strStream3 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
long count = strStream3.count();
复制代码
- anyMatch allMatch noneMatch:对流中元素做比配,返回
boolean
值
Stream<String> strStream1 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
boolean anyMatch = strStream1.anyMatch(x -> x.contains("5"));
Stream<String> strStream2 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
boolean allMatch = strStream2.allMatch(x -> x.contains("5"));
Stream<String> strStream3 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
boolean noneMatch = strStream3.noneMatch(x -> x.contains("5"));
复制代码
- findFirst findAny:
findFirst
返回流中第一个元素,findAny
返回流中任意一个元素,返回类型均为Optional
Stream<String> strStream1 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
Optional<String> findAny = strStream1.findAny();
Stream<String> strStream2 = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
Optional<String> findFirst= strStream2.findFirst();
复制代码
- collect:收集器,可以将流收集为一个值或者一个新的集合
- 归集 toList, toMap, toSet
List<Student> students = new ArrayList<Student>(); students.add(new Student("Jack", "male", 20)); students.add(new Student("Tom", "male", 10)); students.add(new Student("Lily", "female", 30)); students.add(new Student("Anni", "female", 40)); // 归集 List<Student> studentList = students.stream().sorted((o1, o2)->{ return o1.age > o2.age? 1 : -1; }).collect(Collectors.toList()); Map<String, Student> studentMap = students.stream().collect(Collectors.toMap(p-> p.name, p->p)); 复制代码
- 统计
- 计数
count
- 平均值
averagingInt
、averagingLong
、averagingDouble
- 最值
maxBy
、minBy
- 求和
summingInt
、summingLong
、summingDouble
- 计数
// 统计 Long count = students.stream().collect(Collectors.counting()); double avgAge = students.stream().collect(Collectors.averagingInt(p -> p.age)); 复制代码
- 分组 partitionBy groupBy
// 分组 Map<Boolean, List<Student>> studentMap = students.stream().collect( Collectors.partitioningBy(s -> s.age>25) ); Map<String, List<Student>> studentMap2 = students.stream().collect( Collectors.groupingBy(p -> p.gender) ); 复制代码
- 接合 joinning可以连接元素
// 连接 String allName = students.stream().sorted((s1, s2)-> {return s1.age> s2.age? 1 : -1;}) .map(s -> s.name) .collect(Collectors.joining("-")); 复制代码
- flatMap:接收一个函数作为参数,将流中的每个值都换成另外一个流,然后把所有的流连接成一个流,flatMap返回的是一个流
String[] words = new String[]{"Hello", "World"};
// 使用map
Arrays.stream(words)
.map(word -> word.split(""))
.distinct()
.collect(Collectors.toList())
.forEach(System.out::println);
// 使用flatMap
Arrays.stream(words)
.map(word -> word.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList())
.forEach(System.out::println);
复制代码
- reduce:归约,将一个流缩减为一个值
- Optional<T> reduce(BinaryOperator<T> accumulator):对Stream中的数据通过累加器accumulator迭代计算,最终得到一个Optional对象
- T reduce(T identity, BinaryOperator<T> accumulator):给定一个初始值identity,通过累加器accumulator迭代计算,得到一个同Stream中数据同类型的结果
- <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner):给定一个初始值identity,通过累加器accumulator迭代计算,得到一个identity类型的结果,第三个参数用于使用并行流时合并结果
List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4, 10, 50);
// 求和
int sum1 = list.stream().reduce(Integer::sum).get();
int sum2 = list.stream().reduce(10, Integer::sum);
int sum3 = list.stream().parallel().reduce(0, Integer::sum, Integer::sum);
// 求最大值
int max1 = list.stream().reduce(Integer::max).get();
int max2 = list.stream().reduce(100, Integer::max);
int max3 = list.stream().parallel().reduce(0, Integer::max, Integer::max);
复制代码
参考
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END