JAVA8中Stream是对集合对象功能的增强,它主要对集合对象进行高效聚合操作和大批量数据操作且StreamAPI支持Lambda表达式。同时提供串行和并行两种模式进行汇聚操作,能够写出高性能、简洁的多线程代码。
在日常开发中,大部分数据处理都是通过数据库中进行处理,然后取出到内存中使用业务代码进行处理,如:
一些简单的业务逻辑需求可以直接使用RDBMS中进行处理,这样就不用返回到业务代码层进行处理,但是更为复杂的情况下,可能需要脱离RDBMS或者以数据库中返回的数据作为基础然后进一步处理。在JAVA7中我们使用for循环或者Iterator遍历,比较低效。
Stream不是集合元素,不是数据结构不保存数据,Stream类似迭代器,单向,不可重复,流数据只能遍历一次,同时Stream可以进行并发操作。
使用流的步骤是:获取一个数据源➡数据转换➡执行操作获取想要的结果,每次转换原有Stream对象不变,返回一个新的Stream对象,允许对其操作可以像链条一样排列,变成一个管道。
从Collection和数组
从BufferedReader
静态工厂
自己构建
其他
Stream的操作类型:
IntStream、LongStream、DoubleStream
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);
当一个数据元素转换成Stream,就需要对流进行操作了。
Intermediate:map(mapToInt、flatMap)、filter、distinct、sorted、peek、limit、skip、parallel、sequential、unordered
Terminal:forEach、forEachOrdered、toArray、reduce、collect、min、max、cout、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator
Short-circuiting:anyMatch、allMatch、noneMatch、findFirst、findAny、limit
map/flatMap
map即映射,将Stream中的元素转换成另一种元素。map操作将数组中单个单词处理,去重,最后转换为集合返回,最后输出两个String数组。
String[] words = new String[]{"Hello","World"};
List a = Arrays.stream(words)
.map(word -> word.split(""))
.distinct()
.collect(toList());
a.forEach(System.out::print);
flatMap也是映射,但会将Stream中的层级结构扁平化处理。将数组转换成流,使用flatMap对其中每个单词处理,将每个字符取出,然后去重,最后转换为集合返回,最后输出字符串集合。
String[] words = new String[]{"Hello","World"};
List a = Arrays.stream(words)
.flatMap(word -> word.split(""))
.distinct()
.collect(toList());
a.forEach(System.out::print);
filter
对当前流中的元素进行条件过滤,条件为true的元素会被留下汇集成一个新的流。
Integer[] sixNums = {1,2,3,4,5,6};
Integer[] evens = Stream.of(sixNums).filter(n -> n>4).toArray(Integer[]::new);
以上filter操作,大于4的元素被留下,最终生成[5,6]的数组。
forEach
forEach方法是terminal操作,接收一个Lambda表达式,然后Stream上的每一个元素都执行forEach中的Lambda表达式。
Stream.of("1","2","3","4","5").forEach(System.out::print);
以上操作中forEach将流中所有元素都打印出来,且forEach没有返回值。forEach不能修改自己包含的本地变量值,也不能用break/return之类的关键字提前结束循环。。
peek
peek是Intermediate操作,与forEach的执行行为类似,它的存在主要是为了支持调试。对每个元素执行操作并返回一个新的Stream。
Stream.of("1","2","3","4","5").peek(System.out::print).collect(toList());
findFirst
findFirst是terminal兼short-circuiting的方法,总是返回Stream的第一个元素或者空,它返回的是Optional。
Optional integer = Stream.of(1, 2, 3, 4, 5).findFirst();
reduce
reduce作用是将Stream中元素组合起来。它可以传入一个初始值,以初始值为基础,依次根据运算规则处理Stream中元素。例如Stream的sum就相当于
Integer sum = Stream.of(1,2,3,4,5).reduce(0,Integer::sum);
又或者reduce没有传入初始值,仅以此根据运算规则处理Stream中元素,最后返回Optional对象。
Optional optional = Stream.of(1,2,3,4,5).reduce(Integer::sum);
limit返回Stream前面的n的元素;skip是去除前面n个元素。
List limitList = Stream.of(1, 2, 3, 4, 5, 6).limit(3).collect(toList());
List skipList = Stream.of(1,2,3,4,5,6).skip(3).collect(toList());
对Stream的排序通过sorted进行,入参是比较大小的排序逻辑,它的优点就是可以在Stream被map、filter、limit后再排序。
List sortedList = Stream.of(1, 2, 3, 4, 5, 6).sorted(Integer::compare).collect(toList());
min:返回元素中最小的元素;
max:返回元素中最大的元素;
distinct:去除重复的元素,返回的元素在其列表中是唯一的。
Integer minInt = Stream.of(1, 2, 3, 4, 5, 6).min(Integer::compare).get();
Integer maxInt = Stream.of(1, 2, 3, 4, 5, 6).max(Integer::compare).get();
List disList = Stream.of(1, 1, 2, 3, 4, 5, 6,5).distinct().collect(toList());
allMatch:入参为predicate,Stream中所有元素都符合逻辑判断最终才能返回true。
anyMatch:入参为predicate,Stream中所有元素仅需要一个元素符合逻辑判断最终才能返回true。
noneMatch:入参为predicate,需要Stream中所有元素都不符合逻辑判断最终才能返回true。
boolean allMatch = Stream.of(1, 2, 3, 4, 5, 6).allMatch(x -> x > 3);
boolean anyMatch = Stream.of(1, 2, 3, 4, 5, 6).anyMatch(x -> x > 3);
boolean noneMatch = Stream.of(1, 2, 3, 4, 5, 6).noneMatch(x -> x > 3);
Stream.generate
通过Supplier接口,自己控制流的生成,通常用于随机数、常量的Stream或需要前后元素间维持着某种状态信息的Stream。把Supplier实例传递给Stream.generate()生成的Stream,默认是串行(相对parallel而言)但无序的(相对ordered而言)。由于它是无限的,在管道中,必须利用limit之类的操作限制Stream大小。
Random seed = new Random();
Supplier random = seed::nextInt;
Stream.generate(random).limit(10).forEach(System.out::println);
Stream.iterate
generate与reduce方式类似,有个初始值入参,然后以初始值为基础,传入的lambda表达式为逻辑操作进行迭代处理。如初始值是第一个元素,f(seed)为第二个元素,ff((seed))为第三个元素,以此类推。
Stream.iterate(0, n -> n + 3).limit(10).forEach(System.out::print);
java.util.stream.Collectors类主要是辅助进行有用的reduction,如转变输出为Collection,将Stream元素进行归组。
groupingBy/partitioningBy
groupingBy以元素中的某个属性作为分组条件进行分组返回列表,如有映射关系的Map
Map> userGroups = Stream.generate(new UserSupplier()).limit(100).collect(Collectors.groupingBy(User::getAge));
partitioningBy
partitioningBy可以看作特殊的groupingBy,只根据true/false进行分组,返回类型是Map
Map> children = Stream.generate(new PersonSupplier()).limit(100).collect(Collectors.partitioningBy(p -> p.getAge() < 18));
JDK1.8中的Stream详解_DoubleFJ の Blog-CSDN博客_jdk1.8 stream